package com.vt.kakao.login;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.ListView;

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

import com.kakao.auth.ApprovalType;
import com.kakao.auth.AuthType;
import com.kakao.auth.IApplicationConfig;
import com.kakao.auth.ISessionCallback;
import com.kakao.auth.ISessionConfig;
import com.kakao.auth.KakaoAdapter;
import com.kakao.auth.KakaoSDK;
import com.kakao.auth.Session;
import com.kakao.network.ErrorResult;
import com.kakao.usermgmt.UserManagement;
import com.kakao.usermgmt.callback.MeV2ResponseCallback;
import com.kakao.usermgmt.response.MeV2Response;
import com.kakao.util.exception.KakaoException;
import org.json.JSONException;
import java.util.List;

// https://github.com/taejaehan/Cordova-Kakaotalk-Plugin/blob/master/src/android/KakaoTalk.java

@NativePlugin(
        requestCodes={KakaoLogin.REQUEST_CODE}
)
public class KakaoLogin extends Plugin {


    protected static final int REQUEST_CODE = 1001;
    private static final String LOG_TAG = "KakaoTalkCapacitor";
    private static volatile Activity currentActivity;
    private KakaoMeV2ResponseCallback kakaoMeV2ResponseCallback;


    public static Activity getCurrentActivity()
    {
        return currentActivity;
    }


    @Override
    public void load() {
        Log.v(LOG_TAG, "kakao : initialize");

        currentActivity = this.getActivity();
        try {
            KakaoSDK.init(new KakaoSDKAdapter());
            KakaoResources.initResources(currentActivity.getApplication());
        } catch (Exception e) {
            Log.e(LOG_TAG, e.toString());
        }
    }

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

        Log.v(LOG_TAG, "kakao : onActivityResult : " + requestCode + ", code: " + resultCode);
        Session.getCurrentSession().handleActivityResult(requestCode, resultCode, data);
    }

    @PluginMethod()
    public void login(final PluginCall call) {
        Log.v(LOG_TAG, "kakao : execute Login");

        removeSessionCallback();

        kakaoMeV2ResponseCallback = new KakaoMeV2ResponseCallback(call) {
            @Override
            public void onFailure(ErrorResult errorResult) {
                loginProcess(call);
            }

            @Override
            public void onSessionClosed(ErrorResult errorResult) {
                loginProcess(call);
            }
        };
        UserManagement.getInstance().me(kakaoMeV2ResponseCallback);

        saveCall(call);
    }
    private void removeSessionCallback() {
        Session.getCurrentSession().clearCallbacks();
    }
    private void loginProcess(final PluginCall callbackContext) {

        try {
            Session.getCurrentSession().addCallback(new SessionCallback(callbackContext));

            onClickLoginButton(null);

            /*
            final JSONObject parameters = options.getJSONObject(0);
            if (parameters.has("authTypes")) {
                JSONArray authTypes = new JSONArray(parameters.getString("authTypes"));
                setCustomAuthTypes(authTypes);
            }
            onClickLoginButton(getAuthTypes());
             */

        } catch (Exception e) {
            e.printStackTrace();
            KakaoCapacitorErrorHandler.errorHandler(callbackContext, new ErrorResult(e));
        }
    }

    private void onClickLoginButton(final List<AuthType> authTypes) {
        openSession(AuthType.KAKAO_TALK);
        /*
        if (authTypes.size() == 1) {
            openSession(authTypes.get(0));

        } else {
            final Item[] authItems = createAuthItemArray(authTypes);
            ListAdapter adapter = createLoginAdapter(authItems);
            final Dialog dialog = createLoginDialog(authItems, adapter);
            dialog.show();
        }

         */
    }

    /**
     * 실제로 유저에게 보여질 dialog 객체를 생성한다.
     *
     * @param authItems 가능한 AuthType들의 정보를 담고 있는 Item array
     * @param adapter   Dialog의 list view에 쓰일 adapter
     * @return 로그인 방법들을 팝업으로 보여줄 dialog
     */
    private Dialog createLoginDialog(final Item[] authItems, final ListAdapter adapter) {

        final Dialog dialog = new Dialog(this.getActivity(), KakaoResources.LoginDialog);
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        dialog.setContentView(KakaoResources.layout_login_dialog);
        if (dialog.getWindow() != null) {
            dialog.getWindow().setGravity(Gravity.CENTER);
        }

        ListView listView = dialog.findViewById(KakaoResources.login_list_view);
        listView.setAdapter(adapter);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                final AuthType authType = authItems[position].authType;
                if (authType != null) {
                    openSession(authType);
                }
                dialog.dismiss();
            }
        });

        Button closeButton = dialog.findViewById(KakaoResources.login_close_button);
        closeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dialog.dismiss();
            }
        });
        return dialog;
    }

    public void openSession(final AuthType authType) {
        Session.getCurrentSession().open(authType, currentActivity);

    }

    private void requestMe(final PluginCall call) {

        Session.getCurrentSession().addCallback(new SessionCallback(call));
        kakaoMeV2ResponseCallback = new KakaoMeV2ResponseCallback(call);
        UserManagement.getInstance().me(kakaoMeV2ResponseCallback);

    }

    private class SessionCallback implements ISessionCallback {

        private PluginCall call;

        public SessionCallback(final PluginCall call) {
            this.call = call;
        }

        @Override
        public void onSessionOpened() {
            requestMe(call);
        }

        @Override
        public void onSessionOpenFailed(KakaoException exception) {

            if (exception != null) {
                if (exception.toString()
                        .contains("App restarted during Kakao login procedure. Restarting from the start.")) {

                } else {
                    KakaoCapacitorErrorHandler.errorHandler(call, exception.toString());
                }
            }
        }
    }

    private class KakaoMeV2ResponseCallback extends MeV2ResponseCallback {

        private PluginCall call;

        public KakaoMeV2ResponseCallback(final PluginCall call) {
            this.call = call;
        }

        @Override
        public void onFailure(ErrorResult errorResult) {
            KakaoCapacitorErrorHandler.errorHandler(call, errorResult);
        }

        @Override
        public void onSessionClosed(ErrorResult errorResult) {
            KakaoCapacitorErrorHandler.errorHandler(call, errorResult);
            Session.getCurrentSession().checkAndImplicitOpen();
        }

        @Override
        public void onSuccess(MeV2Response response) {
            Log.i("onSuccess", response.toString());
            call.success(handleLoginResult(response, Session.getCurrentSession().getTokenInfo().getAccessToken()));
        }

    }

    private JSObject handleLoginResult(MeV2Response meV2Response, String accessToken) {
        Log.v(LOG_TAG, "JSObject : handleLoginResult");
        JSObject response = new JSObject();
        try {
            response = new JSObject(meV2Response.toString());
            response.put("accessToken", accessToken);
            Log.v(LOG_TAG, "kakao response: " + response);
        } catch (JSONException e) {
            Log.v(LOG_TAG, "kakao : handleResult error - " + e.toString());
        }
        return response;
    }

    private static class KakaoSDKAdapter extends KakaoAdapter {

        @Override
        public ISessionConfig getSessionConfig() {
            return new ISessionConfig() {
                @Override
                public AuthType[] getAuthTypes() {
                    return new AuthType[]{AuthType.KAKAO_LOGIN_ALL};
                }

                @Override
                public boolean isUsingWebviewTimer() {
                    return false;
                }

                @Override
                public ApprovalType getApprovalType() {
                    return ApprovalType.INDIVIDUAL;
                }

                @Override
                public boolean isSecureMode() {
                    return false;
                }

                @Override
                public boolean isSaveFormData() {
                    return false;
                }
            };
        }

        @Override
        public IApplicationConfig getApplicationConfig() {
            return new IApplicationConfig() {
                @Override
                public Context getApplicationContext() {
                    return KakaoLogin.getCurrentActivity().getApplicationContext();
                }
            };
        }
    }

    private static class Item {
        final int textId;
        public final int icon;
        final int contentDescId;
        final AuthType authType;

        Item(final int textId, final Integer icon, final int contentDescId, final AuthType authType) {
            this.textId = textId;
            this.icon = icon;
            this.contentDescId = contentDescId;
            this.authType = authType;
        }
    }
}
