package com.example.iot_controlhost.utils;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;

import androidx.appcompat.app.AppCompatDelegate;

import com.blankj.utilcode.util.ActivityUtils;
import com.blankj.utilcode.util.AppUtils;
import com.blankj.utilcode.util.StringUtils;
import com.blankj.utilcode.util.Utils;
import com.example.iot_controlhost.MyApp;
import com.example.iot_controlhost.R;
import com.example.iot_controlhost.adapter.ModelsAdapter;
import com.example.iot_controlhost.base.BaseMode;
import com.example.iot_controlhost.model.Device;
import com.example.iot_controlhost.model.controller.Controller;
import com.example.iot_controlhost.model.controller.relay.Relay;
import com.example.iot_controlhost.model.thread.QueueIOUITask;
import com.example.iot_controlhost.ui.fragment.AutoFragment;
import com.example.iot_controlhost.ui.fragment.IntelligenceFragment;
import com.example.iot_controlhost.ui.fragment.ManualFragment;
import com.example.iot_controlhost.utils.database.dynamicSensor.IndoorAmmoniaSensorUtil;
import com.example.iot_controlhost.utils.database.dynamicSensor.IndoorCO2SensorUtil;
import com.example.iot_controlhost.utils.database.dynamicSensor.IndoorFloorTSensorUtil;
import com.example.iot_controlhost.utils.database.dynamicSensor.IndoorTHSensorUtil;
import com.example.iot_controlhost.utils.global.HardwareSetting;
import com.example.iot_controlhost.utils.global.RoomController;
import com.example.iot_controlhost.utils.global.RoomSensor;
import com.example.iot_controlhost.utils.global.RoomSetting;
import com.example.iot_controlhost.utils.global.RxTag;
import com.example.iot_controlhost.utils.log.MyLog;
import com.example.iot_controlhost.utils.log.UserLog;
import com.example.iot_controlhost.utils.mainboard.MyAPIContext;
import com.jakewharton.processphoenix.ProcessPhoenix;
import com.luckycatlabs.sunrisesunset.SunriseSunsetCalculator;
import com.luckycatlabs.sunrisesunset.dto.Location;
import com.xuexiang.rxutil2.rxbus.RxBusUtils;
import com.xuexiang.rxutil2.rxjava.RxJavaUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

import es.dmoral.toasty.Toasty;
import me.samlss.broccoli.Broccoli;
import me.samlss.broccoli.BroccoliGradientDrawable;
import me.samlss.broccoli.PlaceholderParameter;

public class MyUtil {

    /**
     * 在温湿度目标值变化时，返回最大值和最小值应该的变化值
     *
     * @param targetOld
     * @param targetDelta
     * @param nowMax
     * @param nowMin
     * @param type
     * @return
     */
    public static double[] getTHMinMax(double targetOld, double targetDelta, double nowMax, double nowMin, double type) {
        double max = 100;
        double min = 0;
        double targetDeltaLimit = 5;
        if (type == 0) {
            max = 33;
            min = 17;
            targetDeltaLimit = 1;
        }
        // 计算target与现有最大值和最小值的偏移
        double resultMax = nowMax + targetDelta;
        // 最大值超过自定义范围 或者  超过规定最大值 则取规定最大值
        if (targetOld + targetDelta >= max - targetDeltaLimit || resultMax > max) {
            resultMax = max;
        }
        double resultMin = nowMin + targetDelta;
        // 最小值超过自定义范围 或者  超过规定最小值 则取规定最小值
        if (targetOld + targetDelta <= min + targetDeltaLimit || resultMin < min) {
            resultMin = min;
        }
        double resultTarget = targetOld + targetDelta;
        if (resultTarget >= max) {
            resultTarget = max;
        }
        if (resultTarget <= min) {
            resultTarget = min;
        }
        return new double[]{resultMin, resultTarget, resultMax};
    }


    /**
     * 获得端口下配置的设备
     *
     * @param port
     * @return 设备名
     */
    public static String getPortToDeviceName(int port) {
        for (Relay controller : RoomController.getAllRelayDevice()) {
            for (int controllerPort : controller.getPorts()) {
                if (controllerPort == port) {
                    return controller.getName();
                }
            }
        }
        return "--";
    }

    /**
     * 校验红外指令正确与否
     */
    public static boolean checkInstruction(String instruction) {
        //如果全为0或者全为F
        if (StringUtils.isEmpty(instruction) || instruction.replaceAll("0", "").equals("") || instruction.replaceAll("F", "").equals("")) {
            return false;
        }
        return true;
    }

    /**
     * 切换亮暗色调
     *
     * @param isDark 是否为黑色调
     */
    public static void switchDarkMode(boolean isDark) {
        if (isDark) {
            // 切换到暗色主题
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
            MMKVUtil.put(RoomSetting.IS_DARK_THEME, true);
        } else {
            // 切换到浅色主题
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
            MMKVUtil.put(RoomSetting.IS_DARK_THEME, false);
        }
    }

    public static Broccoli getMyBroccoli(View... v) {
        Broccoli broccoli = new Broccoli();
        for (int i = 0; i < v.length; i++) {
            broccoli.addPlaceholders(new PlaceholderParameter.Builder()
                    .setView(v[i])
                    .setDrawable(new BroccoliGradientDrawable(Color.parseColor("#DDDDDD"),
                            Color.parseColor("#CCCCCC"), 0, 1000, new LinearInterpolator()))
                    .build());
        }
        return broccoli;
    }

    /**
     * 获得目标模式名
     */
    public static String getModeName(int i) {
        switch (i) {
            case 0:
                return "手动";
            case 1:
                return "自动";
            case 2:
                return "智能";
            default:
                return "";
        }
    }

    /***
     * 获得格式化后的时间
     */
    public static int[] getHourAndMinuteUsingLocalTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        int minute = calendar.get(Calendar.MINUTE);

        return new int[]{hour, minute};
    }


    /**
     * 获取当前版本号
     */
    public static int getVersion(Context context) {
        try {
            PackageManager packageManager = context.getPackageManager();
            PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
            return packageInfo.versionCode;
        } catch (Exception e) {
            e.printStackTrace();
            return -1;
        }
    }


    /**
     * 获取当前版本号
     */
    public static String getVersionId(Context context) {
        try {
            PackageManager packageManager = context.getPackageManager();
            PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
            return String.valueOf(packageInfo.versionCode);
        } catch (Exception e) {
            e.printStackTrace();
            return "Err";
        }
    }

    /**
     * 获取当前版本名称
     */
    public static String getVersionName(Context context) {
        try {
            PackageManager packageManager = context.getPackageManager();
            PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
            return packageInfo.versionName;
        } catch (Exception e) {
            e.printStackTrace();
            return "Err";
        }
    }

    /**
     * 获取当前时间
     */
    public static String getDateTime() {
        return getDateTime(new Date());
    }

    public static String getDateTime(Date date) {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
    }

    /**
     * 获取当前日期
     */
    public static String getDateDay() {
        return new SimpleDateFormat("yyyy-MM-dd").format(new Date());
    }

    /**
     * 转换date格式为标准时间String
     */
    public static String getFormatDateTime(Date date) {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
    }

    public static void changeIcon(Context context, ImageView iv, boolean state, LinearLayout ll_auto_set_param, LinearLayout ll_auto_set_param_none) {
        iv.setImageDrawable(context.getDrawable(state ? R.mipmap.on : R.mipmap.off));
        ll_auto_set_param.setVisibility(state ? View.VISIBLE : View.GONE);
        ll_auto_set_param_none.setVisibility(state ? View.GONE : View.VISIBLE);
    }

    public static void changeIcon(Context context, ImageView iv, LinearLayout ll_auto_set_param, LinearLayout ll_auto_set_param_none) {
        changeIcon(context, iv, !iv.getDrawable().getConstantState().equals(context.getDrawable(R.mipmap.on).getConstantState()), ll_auto_set_param, ll_auto_set_param_none);
    }

    /**
     * 关闭APP
     */
    public static void exitApp() {
        UserLog.system("本机屏幕", "关闭软件");
        MyLog.app("软件生命周期：收到本机关闭软件指令，开始停止自动控制和设备输出");
        MyUtil.stopAppControl("正在关闭软件中", () -> AppUtils.exitApp());
    }

    /**
     * 重启APP
     */
    public static void relaunchApp() {
        relaunchApp("本机屏幕");
    }

    public static void relaunchApp(String source) {
        UserLog.system(source, "重启软件");
        MyLog.app("软件生命周期：收到重启软件指令，来源=" + source + "，开始停止自动控制和设备输出");
        MyUtil.stopAppControl("正在重启软件中", () -> {
//            AppUtils.relaunchApp(); // 这个方法重启不干净
            ProcessPhoenix.triggerRebirth(MyApp.getAppContext());
        });
    }

    /**
     * 关闭设备
     */
    public static void shutDown() {
        shutDown("本机屏幕");
    }

    public static void shutDown(String source) {
        UserLog.system(source, "关闭设备");
        MyLog.app("主机生命周期：收到关闭设备指令，来源=" + source + "，开始停止自动控制和设备输出");
        //先关闭所有设备
        MyUtil.stopAppControl("正在关闭设备中", () -> MyAPIContext.getInstance().shutDown());
    }

    /**
     * 重启设备
     */
    public static void reboot() {
        reboot("本机屏幕");
    }

    public static void reboot(String source) {
        UserLog.system(source, "重启设备");
        MyLog.app("主机生命周期：收到重启设备指令，来源=" + source + "，开始停止自动控制和设备输出");
        MyUtil.stopAppControl("正在重启设备中", () -> MyAPIContext.getInstance().reBoot());
    }

    /**
     * 停止APP的控制
     * 于进入配置或离开关闭设备时使用
     */
    public static void stopAppControl(String tips, Runnable runnable) {
        DialogUtil.showLoadingDialog(ActivityUtils.getTopActivity(), tips);
        MyQueue.start(MyQueue.TYPE_CONTROLLER, new QueueIOUITask<>() {
            @Override
            public Object doInQueueThread() {
                //关闭单独设备
                ModelsAdapter.getModeByPosition(RoomSetting.getMode()).stopMode();
                // 关闭RxBus监听
                RxBusUtils.get().unregisterAll(RxTag.UPDATE_MAIN);
                RxBusUtils.get().unregisterAll(RxTag.UPDATE_AUTO);
                RoomController.floor.setPowerSupply(false);
                //关闭串口 因为关掉串口后会导致部分设备无法关闭 暂时注释
//                    SerialPortUtil.getInstance(SerialPortUtil.TYPE_SENSOR).close();
//                    SerialPortUtil.getInstance(SerialPortUtil.TYPE_CONTROLLER).close();
                return null;
            }

            @Override
            public void doInUIThread(Object o) {
                DialogUtil.hideLoadingDialog();
                runnable.run();
            }
        });
    }

    /**
     * 直接关闭某个设备
     */
    public static boolean autoControlOperateThird(Controller controller) {
        return autoControlOperateThird(controller, false);
    }

    public static boolean autoControlOperateThird(Controller controller, boolean targetState) {
        return autoControlOperateThird(controller, targetState, true);
    }

    /**
     * 自动模式下的操作
     * 最多连续错误三次，否则输出错误日志
     *
     * @param controller  被操作的设备
     * @param targetState 目标状态
     * @param needAutoLog 是否需要输出"自动"日志
     * @return
     */
    public static boolean autoControlOperateThird(Controller controller, boolean targetState, boolean needAutoLog) {
        if (!controller.isAvailable()) {
            // 聚合设备（例如换气扇总控）会自行跳过未安装的子设备，避免每轮自动控制重复报错。
            if (needAutoLog) {
                MyLog.autoError("自动控制跳过：设备=" + controller.getName() + "，目标="
                        + (targetState ? "开启" : "关闭") + "，原因=设备不可用");
            }
            return false;
        }
        boolean previousState = controller.isPowerSupply();
        int maxCount = 3;
        int count = 0;
        boolean success = false;
        if (controller.isPowerSupply() != targetState) {
            // 只有在状态不一致时方才输出日志
            MyLog.auto((needAutoLog ? "自动：" : "") + (targetState ? "开启" : "关闭") + controller.getName());
        }
        while (count < maxCount) {
            count++; // 将计数器递增放在循环开始处
            if (controller.setPowerSupply(targetState)) {
                success = true;
                // 成功后退出循环
                break;
            }
        }
        if (!success) {
            MyLog.autoError((needAutoLog ? "自动" : "系统联动") + "操作(连续" + maxCount + "次)失败："
                    + (targetState ? "开启" : "关闭") + controller.getName());
            if (needAutoLog) {
                UserLog.systemError("自动控制", "设备操作失败：" + controller.getName() + "，状态="
                        + (previousState ? "开启" : "关闭") + " → " + (targetState ? "开启" : "关闭"));
            }
        } else if (needAutoLog && previousState != targetState) {
            UserLog.system("自动控制", "设备状态变化：" + controller.getName() + "，"
                    + (previousState ? "开启" : "关闭") + " → " + (targetState ? "开启" : "关闭"));
            MyLog.auto("自动控制状态确认：设备=" + controller.getName() + "，原状态="
                    + (previousState ? "开启" : "关闭") + "，目标状态="
                    + (targetState ? "开启" : "关闭") + "，尝试次数=" + count + "，结果=成功");
        }
        //自动操作完设备需要更新UI
        RxBusUtils.get().post(RxTag.UPDATE_AUTO, 2);
        return success;
    }

    /**
     * 保存字符串至“下载”文件夹中
     *
     * @param context  上下文
     * @param content  字符串
     * @param fileName 文件名
     */
    public static void saveStringToTxtFile(Context context, String content, String fileName) {
        File downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
        if (!downloadDir.exists()) {
            downloadDir.mkdirs();
        }
        File file = new File(downloadDir, fileName);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(content.getBytes());
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * @param latitude  纬度
     * @param longitude 经度
     */
    public static void calculateSunriseSunset(double latitude, double longitude) {
        //成都坐标
        Location location = new Location(latitude, longitude);
        // 创建日出日落计算器对象
        SunriseSunsetCalculator calculator = new SunriseSunsetCalculator(location, TimeZone.getDefault());
        // 获取日出时间
        String sunrise = calculator.getOfficialSunriseForDate(Calendar.getInstance());
        // 获取日落时间
        String sunset = calculator.getOfficialSunsetForDate(Calendar.getInstance());
        MyLog.test("日出时间：" + sunrise);
        MyLog.test("日落时间：" + sunset);
    }

    /**
     * 检查设备重名
     */
    public static boolean checkDeviceNameAvailable(String name) {
        List<Device> devices = new ArrayList<>();
        // 检查继电器
        devices.addAll(RoomController.getAllRelayDevice());
        // 检查控制器
        devices.add(RoomController.airCondition);
        devices.add(RoomController.floor);
        devices.add(RoomController.airConditionInfrared);
        devices.add(RoomController.airConditionInfrared2);
        devices.add(RoomController.dehumidifierInfrared);
        devices.add(RoomController.dehumidifier485);
        devices.add(RoomController.relayFloor);
        // 检查固定传感器
        Collections.addAll(devices, RoomSensor.outdoorTHSensor, RoomSensor.consumptionSensor, RoomSensor.airTHSensor, RoomSensor.co2OutdoorSensor);
        // 检查动态传感器
        devices.addAll(IndoorTHSensorUtil.getAllSensors());
        devices.addAll(IndoorCO2SensorUtil.getAllSensors());
        devices.addAll(IndoorAmmoniaSensorUtil.getAllSensors());
        devices.addAll(IndoorFloorTSensorUtil.getAllSensors());
        for (Device device : devices) {
            if (device.getName().equals(name)) {
                return false;
            }
        }
        return true;
    }


    public static void relaunchFrp() {
        Context context = ActivityUtils.getTopActivity();
        if (context == null) {
            context = MyApp.getAppContext();
        }
        if (context == null) {
            MyLog.frpError("启动FRP失败：无法获取应用上下文");
            return;
        }
        Context launchContext = context;
        try {
            Intent stopIntent = new Intent("receiver_control");
            stopIntent.putExtra("control", -1);
            launchContext.sendBroadcast(stopIntent);
        } catch (Exception e) {
            MyLog.frpError("发送FRP停止指令失败：" + e.getMessage());
        }
        // 等待2s让FRP释放资源，然后重新启动。
        RxJavaUtils.delay(2, aLong -> {
            try {
                Intent launchIntent = launchContext.getPackageManager()
                        .getLaunchIntentForPackage("com.bbitcn.bbit_frp2");
                if (launchIntent == null) {
                    MyLog.frpError("启动FRP失败：未找到远程协助应用");
                    return;
                }
                launchIntent.putExtra("host_id", HardwareSetting.getHostId());
                launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                launchContext.startActivity(launchIntent);
            } catch (Exception e) {
                MyLog.frpError("启动FRP失败：" + e.getMessage());
            }
        });
    }
}
