package com.dwlrathod.inappupdates;

import android.app.Activity;
import android.content.Intent;
import android.content.IntentSender;
import android.util.Log;

import com.getcapacitor.JSObject;
import com.getcapacitor.NativePlugin;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;

import com.google.android.play.core.appupdate.AppUpdateInfo;
import com.google.android.play.core.appupdate.AppUpdateManager;
import com.google.android.play.core.appupdate.AppUpdateManagerFactory;

import com.google.android.play.core.install.InstallState;
import com.google.android.play.core.install.InstallStateUpdatedListener;

import com.google.android.play.core.tasks.OnFailureListener;
import com.google.android.play.core.tasks.OnSuccessListener;

import com.google.android.play.core.install.model.AppUpdateType;
import com.google.android.play.core.install.model.InstallErrorCode;
import com.google.android.play.core.install.model.InstallStatus;
import com.google.android.play.core.install.model.UpdateAvailability;

@NativePlugin(requestCodes = {InAppUpdatesPlugin.RESULT_FLEXIBLE_UPDATE, InAppUpdatesPlugin.RESULT_IMMEDIATE_UPDATE})
public class InAppUpdatesPlugin extends Plugin {

    private static final String TAG = "InAppUpdatesPlugin:";

    private AppUpdateManager mAppUpdateManager = null;
    private AppUpdateInfo appUpdateInfo = null;
    private InstallStateUpdatedListener installStateUpdatedListener = null;

    private Activity activity = null;

    static final int RESULT_FLEXIBLE_UPDATE = 23;
    static final int RESULT_IMMEDIATE_UPDATE = 24;

    @Override
    public void load() {
        super.load();
        activity = getActivity();
    }

    @PluginMethod()
    public void checkForUpdate(final PluginCall call) {

        mAppUpdateManager = AppUpdateManagerFactory.create(getContext());
        mAppUpdateManager.getAppUpdateInfo()
                .addOnSuccessListener(new OnSuccessListener<AppUpdateInfo>() {
                    @Override
                    public void onSuccess(AppUpdateInfo result) {
                        appUpdateInfo = result;

                        JSObject ret = new JSObject();
                        ret.put("updateAvailable", appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE);
                        ret.put("availableUpdateVersionCode", appUpdateInfo.availableVersionCode());
                        ret.put("flexibleUpdateAllowed", appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE));
                        ret.put("immediateUpdateAllowed", appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE));
                        ret.put("availableUpdatePriority", appUpdateInfo.updatePriority());

                        call.success(ret);
                    }
                }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(Exception e) {
                Log.d(TAG, "onFailure: " + e.getLocalizedMessage());
                call.error(e.getLocalizedMessage());
            }
        });

    }

    @Override
    protected void handleOnStop() {
        super.handleOnStop();
        if (mAppUpdateManager != null && installStateUpdatedListener != null) {
            mAppUpdateManager.unregisterListener(installStateUpdatedListener);
        }
    }

    @PluginMethod
    public void startFlexibleUpdate(final PluginCall call) {
        saveCall(call);
        if (checkAppState(call)) {
            if (appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
                try {
                    installStateUpdatedListener = new InstallStateUpdatedListener() {
                        @Override
                        public void onStateUpdate(InstallState state) {
                            if (state.installErrorCode() != InstallErrorCode.NO_ERROR) {
                                call.error("ErrorCode: " + state.installErrorCode());
                            } else {

                                JSObject ret = new JSObject();
                                ret.put("status", state.installStatus());
                                ret.put("bytesDownloaded", state.bytesDownloaded());
                                ret.put("totalBytesToDownload", state.totalBytesToDownload());
                                notifyListeners("flexibleUpdateStateChange", ret);

                                if (state.installStatus() == InstallStatus.DOWNLOADED) {
                                    call.success();
                                } else if (state.installStatus() == InstallStatus.INSTALLED) {
                                    if (mAppUpdateManager != null) {
                                        mAppUpdateManager.unregisterListener(installStateUpdatedListener);
                                        appUpdateInfo = null;
                                        installStateUpdatedListener = null;
                                    }
                                }
                            }
                        }
                    };
                    mAppUpdateManager.registerListener(installStateUpdatedListener);
                    mAppUpdateManager.startUpdateFlowForResult(
                            appUpdateInfo,
                            AppUpdateType.FLEXIBLE,
                            activity,
                            RESULT_FLEXIBLE_UPDATE
                    );
                } catch (IntentSender.SendIntentException e) {
                    call.error(e.getLocalizedMessage(), e);
                }
            } else {
                call.error("no_update_found");
            }
        }
    }


    @PluginMethod
    public void performImmediateUpdate(PluginCall call) {
        saveCall(call);
        if (checkAppState(call)) {
            if (appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
                try {
                    mAppUpdateManager.startUpdateFlowForResult(
                            appUpdateInfo,
                            AppUpdateType.IMMEDIATE,
                            activity,
                            RESULT_IMMEDIATE_UPDATE
                    );
                } catch (IntentSender.SendIntentException e) {
                    call.error(e.getLocalizedMessage(), e);
                }
            } else {
                call.error("no_update_found");
            }
        }
    }

    @PluginMethod
    public void completeFlexibleUpdate(PluginCall call) {
        if (mAppUpdateManager != null) {
            mAppUpdateManager.completeUpdate();
            call.success();
        }
        call.error("call_checkForUpdate");
    }

    private boolean checkAppState(PluginCall call) {
        if (mAppUpdateManager == null) {
            call.error("call_checkForUpdate");
            return false;
        }
        if (appUpdateInfo == null) {
            call.error("call_checkForUpdate");
            return false;
        }
        if (appUpdateInfo.updateAvailability() != UpdateAvailability.UPDATE_AVAILABLE) {
            call.error("no_update_found");
            return false;
        }
        return true;
    }

    @Override
    protected void handleOnActivityResult(int requestCode, int resultCode, Intent data) {
        super.handleOnActivityResult(requestCode, resultCode, data);

        PluginCall savedCall = getSavedCall();
        if (requestCode == RESULT_FLEXIBLE_UPDATE) {
            if (resultCode != -1 && savedCall != null) {
                savedLastCall.error("user_canceled");
            }
        }
        if (requestCode == RESULT_IMMEDIATE_UPDATE) {
            if (savedCall != null) {
                if (resultCode != -1) {
                    savedCall.error("user_canceled");
                } else {
                    savedCall.success();
                }
            }
        }
        appUpdateInfo = null;
    }

}
