package com.police.policedatasystem.util;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class UaCredentialApi {


    /**********************************************以下是统一认证登录时使用的参数字段常量定义*************************************************************/

    /**
     * 统一认证登录接口(统一认证客户端（UAAC）提供)
     */
    public static final String PROVIDER_URI_GET_CREDENTIAL = "content://com.ydjw.ua.getCredential";

    public static final String PARAMS_KEY_UA_VERSION_VALUE = "1";

    public static final String PARAMS_KEY_UA_MESSAGE_ID = "messageId";

    public static final String PARAMS_KEY_UA_VERSION = "version";

    public static final String PARAMS_KEY_UA_APP_ID = "appId";

    public static final String PARAMS_KEY_UA_ORG_ID = "orgId";

    public static final String PARAMS_KEY_UA_NETWORK_AREA_CODE = "networkAreaCode";

    public static final String PARAMS_KEY_UA_PACKAGE_NAME = "packageName";

    public static final String PARAMS_KEY_UA_RET_CODE = "resultCode";

    public static final String PARAMS_KEY_UA_RET_MESSAGE = "message";

    public static final String PARAMS_KEY_THIRD_APP_INFO = "third_app_info";

    public static final int PARAMS_KEY_UA_RET_SUCCESS = 0;

    public static final int PARAMS_KEY_UA_RET_ERROR_PARAMS = -3;

    public static final int PARAMS_KEY_UA_RET_ERROR_NOT_EXISTS = -5;

    public static final int CREDENTIAL_CLIENT_NOT_INSTALLED = -7;

    public static final int PARAMS_KEY_UA_RET_ERROR_OTHER = -99;

    public static final String PARAMS_KEY_UA_APP_CREDENTIAL = "appCredential";

    public static final String PARAMS_KEY_UA_USER_CREDENTIAL = "userCredential";

    public static final String ACTION_SUFFIX_UA_LOGIN = ".ACTION_LOGIN";

    public static final String ACTION_UA_LOGOUT = "com.ydjw.ua.ACTION_LOGOUT";

    /**********************************************以下是统一认证登录时使用的参数字段常量定义*************************************************************/

    private boolean notExists = false;

    public CredentialReqCallBack credentialReqCallBack;

    private String mMessageId;

    private Context mContext;
    private String version = UaCredentialApi.PARAMS_KEY_UA_VERSION_VALUE;
    private String appId;
    private String orgId;
    private String networkAreaCode;


    private static Map<String, String> packageActivityMap = new HashMap<>();

    /**
     * 统一认证应用包名(历史原因，统一认证单点登录功能存在多个客户端)
     */
    private static String uaacPackageName;

    /**
     * 统一认证启动Activity类名
     */
    private static String uaacLoginActivityName;

    static {
        //新版统一认证
        packageActivityMap.put("com.xdja.uaac", "com.xdja.uaac.ui.InitActivity");
        //旧版统一认证
        packageActivityMap.put("com.xdja.unifyauthorize", "com.xdja.unifyauthorize.activity.LoginActivity");
        //安全接入融合版
        packageActivityMap.put("com.xdja.safeclient", "com.xdja.safeclient.frame.SplashActivity");
        //警信内部集成的旧版统一认证
        packageActivityMap.put("com.xdja.jxclient", "com.xdja.unifyauthorize.activity.LoginActivity");
    }

    public UaCredentialApi(Builder builder) {
        this.mContext = builder.mContext;
        this.version = builder.version;
        this.appId = builder.appId;
        this.orgId = builder.orgId;
        this.networkAreaCode = builder.networkAreaCode;
    }

    public static class Builder {
        protected Context mContext;
        protected String version;
        protected String appId;
        protected String orgId;
        protected String networkAreaCode;

        public Builder(Context context) {
            this.mContext = context;
        }

        public Builder setAppId(String appId) {
            this.appId = appId;
            return this;
        }

        public Builder setVersion(String version) {
            this.version = version;
            return this;
        }

        public Builder setOrgId(String orgId) {
            this.orgId = orgId;
            return this;
        }

        public Builder setNetworkAreaCode(String networkAreaCode) {
            this.networkAreaCode = networkAreaCode;
            return this;
        }

        public UaCredentialApi build() {
            return new UaCredentialApi(this);
        }
    }

    public void reqCredential(CredentialReqCallBack reqCallBack) {
        this.credentialReqCallBack = reqCallBack;

        IntentFilter intentFilter = new IntentFilter();
        String pkgName = mContext.getPackageName();
        /**添加登录成功事件监听
         * 当第一次登录，调用【IF-UA-SDK-01】接口可能返回"票据不存在"，此时需要注册监听此事件，
         * 当登录成功后，接收到此事件即可重新调用【IF-UA-SDK-01】获取相关票据
         * */
        intentFilter.addAction(pkgName + ACTION_SUFFIX_UA_LOGIN);

        /**增加登出事件监听
         * 当UA主动账户退出时会发送该事件，此时已经登录应用可以根据自身业务实施退出
         * */
        intentFilter.addAction(pkgName + ACTION_UA_LOGOUT);
        mContext.registerReceiver(uaLoginInReceiver, intentFilter);
        loginUaForCredential(mContext);
    }

    public void release() {
        notExists = false;
        if (uaLoginInReceiver == null) {
            return;
        }
        mContext.unregisterReceiver(uaLoginInReceiver);
    }

    private BroadcastReceiver uaLoginInReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (TextUtils.isEmpty(action)) {
                return;
            }

            if (action.contains(ACTION_SUFFIX_UA_LOGIN) && notExists) {
                loginUaForCredential(mContext);
            }
        }
    };

    /**
     * 【步骤1：IF-UA-SDK-01】获取凭证信息
     * <br>调用此接口获取用户凭证和应用凭证</br>
     * <br>如用户已登录 UA客户端，则直接向应用返回凭证信息</br>
     * <br>如未登录，待登录完成后将通过广播的形式向应用发送用户登录成功广播，此时可以监听广播重新获取凭证信息</br>
     */
    private void loginUaForCredential(Context context) {

        if (!isCredentialProviderExist(context)) {
            credentialReqCallBack.onCredentialCallBack(CREDENTIAL_CLIENT_NOT_INSTALLED, "未找到UA客户端", "", "");
            return;
        }

        notExists = false;
        String messageId = UUID.randomUUID().toString().replace("-","");
        mMessageId = messageId;
        Uri uri = Uri.parse(PROVIDER_URI_GET_CREDENTIAL);
        ContentResolver resolver = context.getContentResolver();
        Bundle params = new Bundle();

        String packageName = context.getPackageName();
        params.putString(PARAMS_KEY_UA_MESSAGE_ID, messageId);
        params.putString(PARAMS_KEY_UA_VERSION, version);
        params.putString(PARAMS_KEY_UA_APP_ID, appId);
        params.putString(PARAMS_KEY_UA_ORG_ID, orgId);
        params.putString(PARAMS_KEY_UA_NETWORK_AREA_CODE, networkAreaCode);
        params.putString(PARAMS_KEY_UA_PACKAGE_NAME, packageName);

        try {
            Bundle result = resolver.call(uri, "", null, params);
            if (result == null) {
                credentialReqCallBack.onCredentialCallBack(PARAMS_KEY_UA_RET_ERROR_OTHER, "获取应用凭证失败,bundle为空", "", "");
                return;
            }
            String messageIdRet = result.getString(PARAMS_KEY_UA_MESSAGE_ID);
            if (!mMessageId.equals(messageIdRet)) {
                credentialReqCallBack.onCredentialCallBack(PARAMS_KEY_UA_RET_ERROR_OTHER, "获取应用凭证失败,messageId不对应", "", "");
                return;
            }

            receiveCredential(result);
        } catch (ActivityNotFoundException activityNotFoundException) {
            activityNotFoundException.printStackTrace();
            receiveCredentialError(null, activityNotFoundException);
        } catch (Exception e) {
            e.printStackTrace();
            receiveCredentialError(null, e);
        }
    }

    private void receiveCredentialError(Bundle result, Exception e) {
        credentialReqCallBack.onCredentialCallBack(PARAMS_KEY_UA_RET_ERROR_OTHER, "调用UA客户端获取凭证接口异常：" + (e == null ? "" : e.getMessage()), "", "");
    }

    /**
     * 【步骤I：IF-UA-SDK-01】处理获取凭证结果
     *
     * @param result
     */
    private void receiveCredential(Bundle result) {

        int resultCode = result.getInt(PARAMS_KEY_UA_RET_CODE);
        if (PARAMS_KEY_UA_RET_SUCCESS == resultCode) {
            String appCredential = result.getString(PARAMS_KEY_UA_APP_CREDENTIAL);
            String userCredential = result.getString(PARAMS_KEY_UA_USER_CREDENTIAL);
            credentialReqCallBack.onCredentialCallBack(resultCode, "", userCredential, appCredential);
            return;
        }

        if (PARAMS_KEY_UA_RET_ERROR_NOT_EXISTS == resultCode) {
            notExists = true;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                Intent intent = new Intent();
                intent.setClassName(uaacPackageName, uaacLoginActivityName);
                final ThirdAppInfo thirdAppInfo = new ThirdAppInfo();
                thirdAppInfo.setMessageId(result.getString(PARAMS_KEY_UA_MESSAGE_ID));
                thirdAppInfo.setPackageName(mContext.getPackageName());
                thirdAppInfo.setAppId(appId);
                thirdAppInfo.setOrgId(orgId);
                thirdAppInfo.setNetworkAreaCode(networkAreaCode);
                thirdAppInfo.setVersion(version);
                intent.putExtra(PARAMS_KEY_THIRD_APP_INFO, thirdAppInfo);
                if (!(mContext instanceof Activity)) {
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                }
                mContext.startActivity(intent);
            }
            return;
        }

        String message = result.getString(PARAMS_KEY_UA_RET_MESSAGE);
        credentialReqCallBack.onCredentialCallBack(resultCode, message, "", "");
    }

    /**
     * 判断凭证Provider是否存在，如果存在获取Provider所在应用的包名
     */
    private static boolean isCredentialProviderExist(Context context) {
        PackageManager packageManager = context.getPackageManager();
        ProviderInfo providerInfo = packageManager.resolveContentProvider(Uri.parse(PROVIDER_URI_GET_CREDENTIAL).getAuthority(), PackageManager.GET_META_DATA);
        if (providerInfo == null) {
            return false;
        } else {
            uaacPackageName = providerInfo.applicationInfo.packageName;
            uaacLoginActivityName = packageActivityMap.get(uaacPackageName);
            return true;
        }
    }

    public interface CredentialReqCallBack {
        void onCredentialCallBack(int resultCode, String message, String userCredential, String appCredential);
    }

}
