package com.emato.ich;

import android.os.Bundle;

import com.cherry.sdk.controller.utils.ScanGunKeyEventHelper;
import com.emato.ich.api.ICSPApi;
import com.emato.ich.api.ICSPClient;
import com.emato.ich.api.ICSPResponseCodeEnum;
import com.emato.ich.contant.SystemConfigConstant;
import com.emato.ich.crash.CrashApplication;
import com.emato.ich.device.DeviceControl;
import com.emato.ich.entity.Cabinet;
import com.emato.ich.entity.Message;
import com.emato.ich.entity.vo.ResponseData;
import com.emato.ich.entity.vo.ShellVo;
import com.emato.ich.local.LocalStorage;
import com.emato.ich.message.ICHPublishClient;
import com.emato.ich.message.ICHSubscribeClient;
import com.emato.ich.message.ICHTopic;
import com.emato.ich.update.APKUpdateDownload;
import com.emato.ich.update.OnDownloadListener;
import com.emato.ich.utils.BaseUtils;
import com.emato.ich.utils.JacksonUtils;
import com.emato.ich.utils.LoggingUtils;
import com.emato.ich.utils.ResourceUtils;
import com.emato.ich.utils.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import androidx.appcompat.app.AppCompatActivity;

import android.provider.SyncStateContract;
import android.util.Log;
import android.view.KeyEvent;

import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;

import com.emato.ich.databinding.ActivityMainBinding;
import com.xuexiang.xupdate.XUpdate;
import com.xuexiang.xupdate.aria.AriaDownloadServiceProxyImpl;
import com.xuexiang.xupdate.aria.AriaDownloader;
import com.xuexiang.xupdate.easy.EasyUpdate;
import com.xuexiang.xupdate.easy.config.UpdateConfig;
import com.xuexiang.xupdate.entity.UpdateEntity;
import com.xuexiang.xupdate.proxy.impl.DefaultUpdateParser;

import android.view.Menu;
import android.view.MenuItem;
import android.view.WindowManager;

import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

public class MainActivity extends AppCompatActivity  {

    private AppBarConfiguration appBarConfiguration;
    private ActivityMainBinding binding;
    public ScanGunKeyEventHelper scanGunKeyEventHelper;
    private final Map<String, Bundle> bundleMap = new ConcurrentHashMap<>();
    private final Map<String, String> configMap = new ConcurrentHashMap<>();

    private static final String TAG = MainActivity.class.getName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        // 强制关闭输入法
        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);

        setContentView(binding.getRoot());

        // 自动重启
        ((CrashApplication) getApplication()).addActivity(MainActivity.this);

        // 获取系统配置
        getSystemConfig();

        ICHPublishClient ichPublishClient = ICHPublishClient.getInstance();
        ICHSubscribeClient ichSubscribeClient = ICHSubscribeClient.getInstance();

        ICHTopic.CLIENT_ID = BaseUtils.getClientId();
        // 订阅主题
//        ICHSubscribeClient ichSubscribeClient = ICHSubscribeClient.getInstance();
        openLocker(ichSubscribeClient, ichPublishClient);

        // 注册柜子信息
        cabinetInfoReport(ichPublishClient);

        // TODO 更新版本监听
        autoUpdateVersion(ichSubscribeClient);

        // TODO 监听shell命令脚本
        executeShell(ichSubscribeClient, ichPublishClient);
    }

    private void getSystemConfig(){
        ICSPClient.getSystemConfig("", BaseUtils.getClientId(), new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                Log.e(TAG, "onFailure: 获取系统配置错误! 网络错误! ", e);
                LoggingUtils.sendErrorLog("业务异常: 获取系统配置错误! 网络错误!  ", e);
            }

            @Override
            public void onResponse
                    (@NotNull Call call, @NotNull Response response) throws IOException {

                try {
                    String parseResponse = ICSPClient.isSuccessfulAndParseResponse(response);
                    ObjectMapper objectMapper = JacksonUtils.objectmapper;
                    ResponseData<Map<String, String>> readValue = objectMapper.readValue(parseResponse, new TypeReference<ResponseData<Map<String, String>>>() {
                    });
                    if (null != readValue && readValue.getCode().equals(ICSPResponseCodeEnum.OK.getCode())) {
                        configMap.putAll(readValue.getData());
                        // 系统配置的session过期时间
                        String time = configMap.get(SystemConfigConstant.deliverer_token_expire_seconds);
                        if (!StringUtils.isNullOrEmpty(time)) {
                            LocalStorage.getInstance().getSession().setTime(Long.parseLong(time));
                        }

                        Log.i(TAG, "onResponse: =====================>获取系统配置成功! ");
                    } else {
                        Log.w(TAG, "onResponse: code==>" + readValue.getCode() + ", msg==>" + readValue.getMsg());
                    }
                } catch (RuntimeException e) {
                    Log.e(TAG, "onResponse: 获取系统配置错误! 未知错误! ", e);
                }
            }
        });
    }

    private void autoUpdateVersion(ICHSubscribeClient ichSubscribeClient) {
        ichSubscribeClient.subscribe(String.format(ICHTopic.APK_UPDATE_PATH, BaseUtils.getClientId()), (msgId, msg) -> {
            try {
//                 String path = new String(msg.getPayload());
                // 发起请求下载APK
                Log.i(TAG, "autoUpdateVersion: =====================>接收到服务器发来更新指令! 开始更新! ");
                UpdateConfig updateConfig = EasyUpdate.getUpdateConfig(getApplication());
                EasyUpdate.create(getBaseContext(), ICSPApi.GET_UPDATE_PATH.getUrl())
                        .updateHttpService(AriaDownloader.getUpdateHttpService(getApplication()))
                        .build()
                        .update();

//                XUpdate.newBuild(this)
//                        .updateUrl(ICSPApi.GET_UPDATE_PATH.getUrl())
//                        .isAutoMode(true) // 如果需要完全无人干预，自动更新，需要root权限【静默安装需要】
//                        .update();
                Log.i(TAG, "autoUpdateVersion: ====================================>更新中! ");
//                APKUpdateDownload.getInstance().downloadAPK(MainActivity.this, getApplication(), path);
            }  catch (Exception e) {
                Log.e(TAG, "onCreate: =====================>更新版本监听失败! ", e);
                LoggingUtils.sendErrorLog("业务异常: 更新版本监听失败! ", e);
            }
        });
    }

    private UpdateEntity getUpdateEntityFromAssets() {
//        UpdateEntity updateEntity = new UpdateEntity();
//        updateEntity.setVersionCode(3);
//
//

        return new DefaultUpdateParser().parseJson(ResourceUtils.readStringFromAssert("update_test.json", getAssets()));
    }

    private void executeShell(ICHSubscribeClient ichSubscribeClient, ICHPublishClient ichPublishClient){
        ichSubscribeClient.subscribe(String.format(ICHTopic.EXECUTE_SHELL_SCRIPT, BaseUtils.getClientId()), (msgId, msg) -> {
            if (msg != null) {
                try {
                    ShellVo shellVo = JacksonUtils.objectmapper.readValue(msg.getPayload(), ShellVo.class);
                    ShellVo result = shellVo;
                    if (shellVo != null && shellVo.getScript() != null && !"".equals(shellVo.getScript()) && shellVo.getScript().length() > 0) {
                        Log.i(TAG, "executeShell: =====================>接到服务端传来命令: " + shellVo.getScript() + ", 参数: " + shellVo.getArgs());
                        BaseUtils.executeShell(shellVo);
                    } else {
                        Log.i(TAG, "executeShell: =====================>接到服务端传来空命令, 不执行! ");
                        result = new ShellVo();
                        result.setResult("命令为空, 不可执行!");
                    }
                    MqttMessage mqttMessage = new MqttMessage();
                    mqttMessage.setQos(1);
                    mqttMessage.setPayload(JacksonUtils.objectmapper.writeValueAsString(result).getBytes());
                    ichPublishClient.publish(String.format(ICHTopic.EXECUTE_SHELL_SCRIPT_RESPONSE, BaseUtils.getClientId()), mqttMessage);
                    Log.i(TAG, "executeShell: =====================>发送命令执行结果成功! ");
                } catch (Exception e) {
                    Log.e(TAG, "onCreate: 发送执行脚本结果失败! ", e);
                    LoggingUtils.sendErrorLog("业务异常: 发送执行脚本结果失败! ", e);
                }
            }
        });
    }

    private void openLocker(ICHSubscribeClient ichSubscribeClient, ICHPublishClient ichPublishClient) {
        ichSubscribeClient.subscribe(ICHTopic.LOCK + BaseUtils.getClientId(), (s, msg) -> {
            String payload = new String(msg.getPayload());
            ObjectMapper objectMapper = JacksonUtils.objectmapper;
            Message message = objectMapper.readValue(payload, Message.class);
            Log.i(TAG, "onCreate: message id: " + s + "--------------消息体: " + message);
            Log.i(TAG, "openLocker: ==================>接到开锁消息: " + message);

            DeviceControl.unlockLocker(message.getSection(), message.getPort(), (var1, var2) -> {
                Log.i(TAG, "onCreate: 开锁返回码: " + var1 + "--------------返回消息: " + Arrays.asList(var2));
                MqttMessage mqttMessage;
                if (var1 != 0) {
                    try {
                        mqttMessage = wrapMessage(message, objectMapper);
                        ichPublishClient.publish(String.format(ICHTopic.CALLBACK_FAILED, BaseUtils.getClientId()), mqttMessage);
                        Log.i(TAG, "openLocker: ==================>发送开锁失败消息成功! 锁板id: " + message.getSection() + ", 端口: " + message.getPort());
                    } catch (JsonProcessingException e) {
                        Log.e(TAG, "onCreate: ---------------------序列化开锁错误消息失败! ", e);
                        LoggingUtils.sendErrorLog("业务异常: 序列化开锁错误消息失败! ", e);
                    } catch (Exception e) {
                        Log.e(TAG, "onCreate: ---------------------未知错误! ", e);
                        LoggingUtils.sendErrorLog("业务异常: 序列化开锁未知错误! ", e);
                    }
                } else {
                    // TODO 暂时不做 成功需要不断去请求查询锁是否关闭, 关闭后推送成功消息
//                    AtomicBoolean atomicBoolean = new AtomicBoolean(true);
//                    AtomicInteger atomicInteger = new AtomicInteger(5);
//                    do {
//                        try {
//                            TimeUnit.SECONDS.sleep(30);
//                        } catch (InterruptedException e) {
//                            Log.e(TAG, "onCreate: 等待查询锁状态时线程中断! ", e);
//                        }
//                        DeviceControl.queryLocker(message.getSection(), message.getPort(), (var3, var4) -> {
//                            List<String> strings = Arrays.asList(var4);
//                            if (var3 == 0 && strings.size() > 0 && !strings.get(0).equals("locked")) {
//                                atomicBoolean.set(false);
//                            }
//                            atomicInteger.decrementAndGet();
//                        });
//                        if (atomicInteger.get() <= 0) {
//                            atomicBoolean.set(false);
//                        }
//                    } while(atomicBoolean.get());
                    try {
                        Log.i(TAG, "onCreate: =====================>开锁成功! 锁板id: " + message.getSection() + ", 端口: " + message.getPort());
                        mqttMessage = wrapMessage(message, objectMapper);
//                        if (atomicInteger.get() <= 0) {
//                            message.setCause("长时间未关闭柜门!");
//                            mqttMessage.setPayload(objectMapper.writeValueAsBytes(message));
//                            ichPublishClient.publish(String.format(ICHTopic.CALLBACK_FAILED, BaseUtils.getClientId()), mqttMessage);
//                        }

                        ichPublishClient.publish(String.format(ICHTopic.CALLBACK_SUCCESS, BaseUtils.getClientId()), mqttMessage);
                    } catch (JsonProcessingException e) {
                        Log.e(TAG, "onCreate: ---------------------序列化开锁成功消息失败! ", e);
                        LoggingUtils.sendErrorLog("业务异常: 序列化开锁成功消息失败! ", e);
                    } catch (RuntimeException e) {
                        Log.e(TAG, "onCreate: ---------------------序列化开锁成功消息未知错误! ", e);
                        LoggingUtils.sendErrorLog("业务异常: 开锁未知错误! ", e);
                    }
                }
            });

        });
    }

    private void cabinetInfoReport(ICHPublishClient ichPublishClient){
        String appVersion = BaseUtils.getAppVersion(getApplicationContext());
        String androidVersion = BaseUtils.getVersionName();
        CountDownLatch countDownLatch = new CountDownLatch(10);
        Cabinet cabinet = DeviceControl.queryCabinetInfo(countDownLatch);
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        cabinet.setClientId(BaseUtils.getClientId());
        cabinet.setSoftwareVersion(appVersion);
        cabinet.setAndroidVersion(androidVersion);
        cabinet.setSoftwareType("android");
        cabinet.setImei(BaseUtils.getIMEI(getApplicationContext()));
        cabinet.setMacIpv4(BaseUtils.getIp());
        cabinet.setMacIpv6("unknown");
        cabinet.setNetType("unknown");
        cabinet.setPlatType("S905");
        cabinet.setSim("unknown");
        cabinet.setWifiSSid("unknown");

        ObjectMapper objectMapper = JacksonUtils.objectmapper;

        try {
            String jsonData = objectMapper.writeValueAsString(cabinet);
            Log.i(TAG, "onCreate: jsonData===============>" + jsonData);

            MqttMessage message = new MqttMessage();
            message.setQos(1);
            message.setPayload(jsonData.getBytes());
            ichPublishClient.publish(String.format(ICHTopic.CABINET_INFO_REPORT, BaseUtils.getClientId()), message);
            Log.i(TAG, "cabinetInfoReport: ===============>上报柜子信息成功! ");
        } catch (JsonProcessingException e) {
            Log.e(TAG, "onCreate: 解析成JSON失败!", e);
            LoggingUtils.sendErrorLog("业务异常: 上报柜子信息时解析成JSON失败! ", e);
        }
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (null != scanGunKeyEventHelper) {
            scanGunKeyEventHelper.analysisKeyEvent(event);
        }
        return true;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
//        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
//        int id = item.getItemId();

//        //noinspection SimplifiableIfStatement
//        if (id == R.id.action_settings) {
//            return true;
//        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onSupportNavigateUp() {
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
        return NavigationUI.navigateUp(navController, appBarConfiguration)
                || super.onSupportNavigateUp();
    }

    private MqttMessage wrapMessage(Message message, ObjectMapper objectMapper) throws JsonProcessingException {
        MqttMessage mqttMessage = new MqttMessage();
        Message failedMsg = new Message();
        // TODO 失败原因枚举
        failedMsg.setCause("失败原因枚举");
        failedMsg.setMessageId(message.getMessageId());
        failedMsg.setClientId(message.getClientId());
        failedMsg.setCmd(message.getCmd());
        failedMsg.setDatetime(message.getDatetime());
        failedMsg.setPort(message.getPort());
        failedMsg.setScene(message.getScene());
        failedMsg.setSection(message.getSection());
        mqttMessage.setQos(1);
        mqttMessage.setPayload(objectMapper.writeValueAsBytes(failedMsg));

        return mqttMessage;
    }

    public Map<String, Bundle> getBundleMap() {
        return bundleMap;
    }

    public Map<String, String> getConfigMap() {
        return configMap;
    }
}