package com.tcl.ah.tvcontrol.service;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresPermission;

import com.tcl.ah.module.config.ProjectIni;
import com.tcl.ah.module.serverinfo.ServerInfoHandler;
import com.tcl.ah.module.serverinfo.data.ServerInfo;
import com.tcl.ah.tvcontrol.Constants;
import com.tcl.ah.tvcontrol.MyApplication;
import com.tcl.ah.tvcontrol.api.ControlConfig;
import com.tcl.ah.tvcontrol.api.KeyEventHelper;
import com.tcl.ah.tvcontrol.broadcast.BootCompletionReceiver;
import com.tcl.ah.tvcontrol.broadcast.NetworkBroadcastReceiver;
import com.tcl.ah.tvcontrol.mqtt.ConstantsMqtt;
import com.tcl.ah.tvcontrol.mqtt.MQTTHelper;
import com.tcl.ah.tvcontrol.mqtt.config.MqttConfig;
import com.tcl.ah.tvcontrol.utils.MqttDataDealUtil;
import com.tcl.ah.tvcontrol.utils.NetUtil;
import com.tcl.ah.tvcontrol.utils.PackageHelper;
import com.tcl.ah.tvcontrol.utils.SharedPrefHelper;
import com.tcl.awesomehotel2.provider.HotelInfoHelper;
import com.tcl.snack.os.SystemProperties;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.json.JSONObject;
import org.reactivestreams.Subscriber;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;

public class MyMqttService extends Service {

    private static String TAG = "DEBUG_MqttService";
    private static final int FLAG_START_MQTT = 1;
    public static final int FLAG_SUBSCRIBE_TOPIC = 2;
    public static final int FLAG_TIME_DELAY = 3;

    //V1.1.5
    public static final int DELAY_TIME = 5 * 1000;
    public static final int DELAY_TIME_1S = 1000;

    private ServerInfoHandler mServerInfoHandler;

    MQTTHelper mqttHelper;

    MqttCallback mqttCallback;


    NetworkBroadcastReceiver networkBroadcastReceiver;

    Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case FLAG_START_MQTT:
                    startMqtt();
                    break;
                case FLAG_SUBSCRIBE_TOPIC:
                    if (mqttHelper != null)
                        mqttHelper.subscribeToTopic();
                    break;
                case FLAG_TIME_DELAY:

                    if (NetUtil.isNetSystemUsable(MyMqttService.this)) {
                        Log.d(TAG, "this is net 可用 start MQTT:");
                        handler.removeMessages(FLAG_START_MQTT);
                        handler.sendEmptyMessageDelayed(FLAG_START_MQTT, DELAY_TIME_1S);
                    } else {
                        Log.d(TAG, "this is net 不可用 start Delay:");
                        delayStartMqtt();
                    }
                    break;
            }
            return false;
        }
    });


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "this is on qtt service onStartCommand");
        delayStartMqtt();

        return START_STICKY;//START_STICKY(intent null)，START_REDELIVER_INTENT

    }

    private void delayStartMqtt() {

        handler.removeMessages(FLAG_TIME_DELAY);
        handler.sendEmptyMessageDelayed(FLAG_TIME_DELAY, DELAY_TIME);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        BootCompletionReceiver.IsStartByBoot = false;
//        if (networkBroadcastReceiver != null) {
//            unregisterReceiver(networkBroadcastReceiver);
//            Constants.IsRegister = false;
//        }
    }


    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "this is onCreate");

        createNotificationForActivity();

        mServerInfoHandler = new ServerInfoHandler();

    }


//    private void registerNet() {
//        networkBroadcastReceiver = new NetworkBroadcastReceiver(this);
//        networkBroadcastReceiver.register();
//        networkBroadcastReceiver.setCallback(new NetworkBroadcastReceiver.Callback() {
//            @Override
//            public void onReceive(Context context, Intent intent) {
//                Log.i(TAG, "this is registerNet");
//                String action = intent.getAction();
//                if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
//                    if (isNetWorkConnected(getApplicationContext())) {
//                        handler.removeMessages(FLAG_START_MQTT);
//                        handler.sendEmptyMessageDelayed(FLAG_START_MQTT, DELAY_TIME);
//                    } else {
//                        Log.i(TAG, "net is disconnect,wait for net");
//                    }
//                }
//
//            }
//        });
//    }

//    @RequiresPermission("android.permission.ACCESS_NETWORK_STATE")
//    public static boolean isNetWorkConnected(Context context) {
//        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
//        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
//        return networkInfo != null && networkInfo.isConnected() && networkInfo.isAvailable();
//    }

    private void getMqttInfoByNetAndConnect() {

        mServerInfoHandler.setMac(NetUtil.getEthMacAddress().toLowerCase())
                .setPackageName("com.tcl.ah.tvcontrol")
                .setUrl(ProjectIni.URL);


        Observable.just("get mqtt")
                .subscribeOn(AndroidSchedulers.mainThread()) ///onNext执行的线程
                .observeOn(Schedulers.newThread())
                .map(s -> {
//                    Log.i("DEBUG_TS", "this is  map thread :" + Thread.currentThread().getId()
//                            + "t:" + Thread.currentThread().toString());

                    try {
                        boolean ret = mServerInfoHandler.get();
                        return ret;
                    } catch (Exception e) {
                        Log.e("DEBUG_TS", "this is ee:" + e.toString());
                        delayStartMqtt();
                    }

                    return false;

                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Boolean>() {
                    @Override
                    public void onSubscribe(Disposable d) {
//                        Log.i("DEBUG_TS", "this is  onSubscribe thread :" + Thread.currentThread().getId()
//                                + "t:" + Thread.currentThread().toString());
                    }

                    @Override
                    public void onNext(Boolean flag) {

                        Log.i("DEBUG_TS", "this is from net mqtt flag:" + flag);
                        if (flag) {
                            ServerInfo mServerInfo = mServerInfoHandler.getServerInfo();
                            Log.i("DEBUG_TS", "this is from net mqtt :" + mServerInfo.mqttInfo.host
                                    + "user:" + mServerInfo.mqttInfo.user
                            );

                            savaMqttInfo(mServerInfo.mqttInfo);

                            initMqttConfigFromNet(mServerInfo.mqttInfo);

                            connectMqtt(initTopic());

                        }
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {
                        Log.i("DEBUG_TS", "this is  onComplete thread :" + Thread.currentThread().getId()
                                + "t:" + Thread.currentThread().toString());
                    }
                });

    }

    private void savaMqttInfo(ServerInfo.MqttInfo mqttInfo) {

        SharedPrefHelper.getInstance(MyApplication.getAppContext()).setKeyMqttIp(mqttInfo.host);
        SharedPrefHelper.getInstance(MyApplication.getAppContext()).setKeyMqttPort(String.valueOf(mqttInfo.port));
        SharedPrefHelper.getInstance(MyApplication.getAppContext()).setKeyMqttUser(mqttInfo.user);
        SharedPrefHelper.getInstance(MyApplication.getAppContext()).setKeyMqttPwd(mqttInfo.password);

    }


    private void startMqtt() {

        try {
            initMqttCallback();


            Log.i("DEBUG_TS", "this is startMqtt: + Version:117 + IsStartByBoot:"
                    + BootCompletionReceiver.IsStartByBoot);

            //初始化mqttInfo
            if (BootCompletionReceiver.IsStartByBoot) {

                getMqttInfoByNetAndConnect();
            } else {
                getMqttInfoByLocal();
                connectMqtt(initTopic());

            }

            //HotelInfoHelper mHotelInfo = new HotelInfoHelper(getApplicationContext());
            //initMqttConfig(mHotelInfo);


        } catch (Exception e) {
            Log.i("DEBUG_TS", "this is startMqtt: " + e.toString());
            handler.removeMessages(FLAG_START_MQTT);
            handler.sendEmptyMessageDelayed(FLAG_START_MQTT, 5000);
        }

    }

    private void getMqttInfoByLocal() {
        String host = SharedPrefHelper.getInstance(MyApplication.getAppContext()).getKeyMqttIp();
        String port = SharedPrefHelper.getInstance(MyApplication.getAppContext()).getKeyMqttPort();
        String user = SharedPrefHelper.getInstance(MyApplication.getAppContext()).getKeyMqttUser();
        String pwd = SharedPrefHelper.getInstance(MyApplication.getAppContext()).getKeyMqttPwd();

        Log.i("DEBUG_TS", "this is getMqttInfoByLocal: " + host + "port:" + port
                + user + "pwd:" + pwd);
        try {
            if (host.length() < 3) return;

            if (host.contains("tcp")) {
                ConstantsMqtt.Mqtt_Ip = host;
            } else {
                ConstantsMqtt.Mqtt_Ip = "tcp://" + host;
            }

            ConstantsMqtt.Mqtt_Port = port;
            ConstantsMqtt.Mqtt_UserName = user;
            ConstantsMqtt.Mqtt_Pwd = pwd;

            Log.i("DEBUG_TS", "this is startMqtt Mqtt_Ip:" + ConstantsMqtt.Mqtt_Ip
                    + "Mqtt_Port:" + ConstantsMqtt.Mqtt_Port
                    + "Mqtt_UserName:" + ConstantsMqtt.Mqtt_UserName
            );
        } catch (Exception e) {
            Log.e("DEBUG_TS", "this is initMqttConfig:" + e.toString());
        }

    }

    private void connectMqtt(String topic) {
        if (topic == null) return;

        String clientId = Constants.MAC.toLowerCase() + "_" + Constants.APP_NAME;
        MqttConfig mConfig = new MqttConfig();
        mConfig.setClientId(clientId)
                .setServerUrl(ConstantsMqtt.Mqtt_Ip + ":" + ConstantsMqtt.Mqtt_Port)
                .setUsername(ConstantsMqtt.Mqtt_UserName)
                .setPassword(ConstantsMqtt.Mqtt_Pwd)
                .setTopic(topic);

        //会导致断连，无法收到消息
        //mqttHelper = MQTTHelper.getInstance(MyApplication.getAppContext(), mConfig, mqttCallback);

        mqttHelper = new MQTTHelper(MyApplication.getAppContext(), mConfig, mqttCallback, handler);
        mqttHelper.doConnect();
    }

    private String initTopic() {
        String hotelId = getHotelId();
        String hotelRoom = getHotelRoom();
        Constants.MAC = NetUtil.getEthMacAddress();
        if (hotelId == null || hotelId.isEmpty() || hotelId.length() < 2) {
            handler.removeMessages(FLAG_START_MQTT);
            handler.sendEmptyMessageDelayed(FLAG_START_MQTT, 10 * 1000);
            return null;
        }
        //todo test
        //String topic = String.format(ConstantsMqtt.TOPIC_TV_CONTROL, "Y020002", "11", "AC5D5C196125".toLowerCase());
        String topic = String.format(ConstantsMqtt.TOPIC_TV_CONTROL, hotelId, hotelRoom, Constants.MAC.toLowerCase());
        Log.i("DEBUG_TS", "this is startMqtt hotelId:" + hotelId
                + "hotelRoom:" + hotelRoom);
        return topic;
    }

    private String getHotelId() {
        try {
            return SystemProperties.get("persist.sys.hotel.id");
        } catch (Exception e) {
            Log.e("DEBUG_TS", "this is getHotelId: " + e.toString());
        }
        return "";
    }

    private String getHotelRoom() {
        try {
            return SystemProperties.get("persist.sys.hotel.room");
        } catch (Exception e) {
            Log.e("DEBUG_TS", "this is getHotelRoom: " + e.toString());
        }
        return "";
    }

    private void initMqttConfigFromNet(ServerInfo.MqttInfo mqttInfo) {
        try {
            if (mqttInfo.host != null && mqttInfo.host.contains("tcp")) {
                ConstantsMqtt.Mqtt_Ip = mqttInfo.host;
            } else {
                ConstantsMqtt.Mqtt_Ip = "tcp://" + mqttInfo.host;
            }

            ConstantsMqtt.Mqtt_Port = String.valueOf(mqttInfo.port);
            ConstantsMqtt.Mqtt_UserName = mqttInfo.user;
            ConstantsMqtt.Mqtt_Pwd = mqttInfo.password;

            Log.i("DEBUG_TS", "this is startMqtt Mqtt_Ip:" + ConstantsMqtt.Mqtt_Ip
                    + "Mqtt_Port:" + ConstantsMqtt.Mqtt_Port
                    + "Mqtt_UserName:" + ConstantsMqtt.Mqtt_UserName
            );
        } catch (Exception e) {
            Log.e("DEBUG_TS", "this is initMqttConfig:" + e.toString());
        }

    }

    private void initMqttConfig(HotelInfoHelper mHotelInfo) {
        try {
            if (mHotelInfo.getMqttHost() == null) return;
            if (mHotelInfo.getMqttHost() != null && mHotelInfo.getMqttHost().contains("tcp")) {
                ConstantsMqtt.Mqtt_Ip = mHotelInfo.getMqttHost();
            } else {
                ConstantsMqtt.Mqtt_Ip = "tcp://" + mHotelInfo.getMqttHost();
            }

            ConstantsMqtt.Mqtt_Port = mHotelInfo.getMqttPort();
            ConstantsMqtt.Mqtt_UserName = mHotelInfo.getMqttUser();
            ConstantsMqtt.Mqtt_Pwd = mHotelInfo.getMqttPassword();

            Log.i("DEBUG_TS", "this is startMqtt Mqtt_Ip:" + mHotelInfo.getMqttHost()
                    + "Mqtt_Port:" + mHotelInfo.getMqttPort()
                    + "Mqtt_UserName:" + mHotelInfo.getMqttUser()
            );
        } catch (Exception e) {
            Log.e("DEBUG_TS", "this is initMqttConfig:" + e.toString());
        }

    }

    private void initMqttCallback() {

        mqttCallback = new MqttCallback() {
            @Override
            public void connectionLost(Throwable cause) {
                Log.i("DEBUG_mqttCallback", "this is connectionLost:");

            }

            @Override
            public void messageArrived(String topic, MqttMessage message) throws Exception {
                Log.i("DEBUG_mqttCallback", "this is message:" + message.toString() + "topic:" + topic);

                String dataString = "";
                String decryptString = "";
                try {
                    JSONObject jsonObject = new JSONObject(message.toString());
                    if (jsonObject.has("data")) {
                        dataString = jsonObject.getString("data");
                        decryptString = decryptMessage(dataString);

                        JSONObject dataObject = new JSONObject(decryptString);
                        parseParams(dataObject);

                    }
                } catch (Exception e) {

                }

            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken token) {
                Log.i("DEBUG_mqttCallback", "this is deliveryComplete for public:");
            }
        };
    }

    //拓展接口处理
    private void parseParams(JSONObject jsonParams) throws Exception {
        String command = "";
        String keyValue = "";
        if (jsonParams.has("code")) {
            command = jsonParams.getString("code");

        }
        if (jsonParams.has("value")) {
            keyValue = jsonParams.getString("value");
        }
        Log.i("DEBUG_TS", "this is command:" + command + "keyValue:" + keyValue);
        //处理调用第三方apk
        if (command.contains(ControlConfig.COMMAND_SET_POWERSTATE)
                || command.contains(ControlConfig.COMMAND_SET_DIRECTION)
                || command.contains(ControlConfig.COMMAND_SET_VOLUME)
                || command.contains(ControlConfig.COMMAND_SET_CHANNEL)
                || command.contains(ControlConfig.COMMAND_SET_HOMEPAGE)
                || command.contains(ControlConfig.COMMAND_SET_BACKTRACK)
                || command.contains(ControlConfig.COMMAND_SET_MENU)
                || command.contains(ControlConfig.COMMAND_SET_SOURCE)
        ) {
            KeyEventHelper.getInstance().dealKeyEvent(command, Integer.valueOf(keyValue));
        } else {

            PackageHelper.startActivityByPackage(keyValue);
        }

    }


    private String decryptMessage(String message) {
        try {
            return MqttDataDealUtil.Base64Decrypt(message);
        } catch (Exception e) {
            Log.e("DEBUG_mqttCallback", "this is decryptMessage :" + e.toString());
        }
        return "";

    }


    private void createNotificationForActivity() {
        NotificationManager notificationManager = (NotificationManager) MyApplication.getAppContext().getSystemService(Context.NOTIFICATION_SERVICE);
        NotificationChannel mChannel = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            mChannel = new NotificationChannel("channelId", "channelName", NotificationManager.IMPORTANCE_HIGH);
            notificationManager.createNotificationChannel(mChannel);
            Notification notification = new Notification.Builder(getApplicationContext(), "channelId").build();
            startForeground(1, notification);
        }
    }


}
