import Taro from "@tarojs/taro";
import classnames from "classnames";

import { Component, PropsWithChildren, useEffect, useState } from "react";
import { Block, View, Text, PageMeta } from "@tarojs/components";
import { Popup, Progress } from "@antmjs/vantui";

import { connect } from "react-redux";
import {
  msg,
  back,
  showModal,
  go,
  loading,
  getStorageSync,
} from "@/utils/traoAPI";
import { InstrumentInfo } from "@/utils/Interface";
import {
  notifyBLECharacteristicValueChange,
  writeBLECharacteristicValue,
  sendCommand,
} from "@/utils/bluetoothWXAPI";
import {
  ab2hex,
  ccrc8,
  filterBleData,
  hex2int,
  string2buffer,
} from "@/utils/util";
import {
  Stringkit,
  TResponseFromDevice,
} from "@flossom-npm/iot-translater-we100";

// 通过设备类型判断给 deviceToolKitInstance  赋值
import { DeviceToolKit as DeviceToolKitWE100 } from "@flossom-npm/iot-translater-we100";
import { DeviceToolKit as DeviceToolKitFR200 } from "@flossom-npm/iot-translater";

import OtaDeviceTypeEnum from "../OtaDeviceTypeEnum";

// 临时替代
var log = console;

let deviceToolKitInstance: any = null;

const deviceToolKitInstanceFR200 = new DeviceToolKitFR200("FR200");
deviceToolKitInstanceFR200.setDebug(true);

import "./index.less";

class UpdateIotFR200 extends Component<any, any> {
  constructor(props) {
    super(props);
    this.state = {
      name: "UpdateIotFR200",
      progressbar: 1, // 进度条

      currentDevice: {},

      hadStartOta: false, // 是否开始ota
    };
  }

  $instance = Taro.getCurrentInstance();
  $checkTimer: any = null;
  // 与页面渲染无关的数据
  $otaDataGroup: any = {
    // 包大小，面罩设置为100，主机设置为240
    packageSize: 240, //每个包的大小上限（单位是字节）
    otaBin: null, //固件包buffer形式，从16进制字符串转换成
    otaHexString: "", //固件包的16进制字符串，从后端接口返回
    packageLength: 0, //升级包的总长度(单位是字节)
    packageCount: 0, //分包后的总包数
    otaData: [], //分包数组
    packageCrc8: "", //总包的校验码
    versionNo: "", //包的版本号
    otaCurrentPackageIndex: 0, //现在正在传输的分包索引
    countDown: 7,
  };

  async onLoad() {
    if (this.$checkTimer) clearInterval(this.$checkTimer);
  }
  componentDidMount() {
    console.log("componentDidMount");
    this.initData();
  }
  componentDidHide() {
    console.log("componentDidHide");
    this.errorFun();
  }

  async initData() {
    console.log("UpdateIotWL200");
    deviceToolKitInstance = deviceToolKitInstanceFR200;

    let objStr = getStorageSync("instrument_detail");
    if (objStr) {
      this.setState({
        currentDevice: objStr,
      });
    }
    setTimeout(() => {
      this.notifyBLECharacteristicValueChange();
      this.getDeviceUpgrade();
    });
  }

  /**
   * 拆分升级包
   */
  async getUpgradeData() {
    //解析获取升级包更新数据
    const { otaHexString, packageSize } = this.$otaDataGroup;
    if (!otaHexString?.length) {
      return [];
    }
    let arr: any = [];
    for (let i = 0, len = otaHexString.length; i < len; i += packageSize * 2) {
      let index = i + packageSize * 2;
      let value = otaHexString.slice(i, index);
      arr.push(value);
    }
    return arr;
  }
  /**
   * 重置OTA状态
   */
  resetOta() {
    this.$otaDataGroup = {
      ...this.$otaDataGroup,
      otaCurrentPackageIndex: 0,
      otaData: [],
    };
  }
  /**
   * 启动ota
   */
  startOTA() {
    this.resetOta();
    let jsoncmd = {
      commandType: "OTAStart",
      otaDeviceType: "FR200",
      versionNo: this.$otaDataGroup.versionNo,
    };

    console.log("startOTA jsoncmd", jsoncmd);

    //@ts-ignore
    const value = deviceToolKitInstance.toBleCommand(jsoncmd as any);
    console.log(jsoncmd);
    sendCommand({ value }).then((res) => {
      this.setState({
        hadStartOta: true,
      });
      this.createTimer();
    });
  }
  /**
   * 准备ota
   */
  preOTA() {
    const { packageCount, packageLength, packageCrc8, versionNo } =
      this.$otaDataGroup;
    let jsoncmd = {
      commandType: "OTAPrepare",
      packageCount,
      packageLength,
      packageCrc8,
      versionNo,
    };
    console.info("OTAPrepare json => ", jsoncmd);
    //@ts-ignore
    const value = deviceToolKitInstance.toBleCommand(jsoncmd as any);
    sendCommand({ value });
  }
  /**
   * ota升级
   */
  processOTA(i, data) {
    const { packageCount, packageLength } = this.$otaDataGroup;
    if (!packageLength) {
      this.quitOTA();
    }
    let jsoncmd = {
      commandType: "OTAUpdating",
      packageCount,
      packageLength,
      currentPackageNo: i + 1,
      currentPackageLength: data.length / 2,
      currentPackageContent: data,
    };
    console.info("OTAUpdating json => ", jsoncmd);
    //@ts-ignore
    const value = deviceToolKitInstance.toBleCommand(jsoncmd as any);
    sendCommand({ value });
  }
  /**
   * ota升级完成
   */
  async finishedOTA() {
    let jsoncmd = {
      commandType: "OTAUpdateFinish",
      versionNo: this.$otaDataGroup.versionNo,
    };
    clearInterval(this.$checkTimer);
    log.info("ota成功日志, 清除计时器");
    //@ts-ignore
    const value = deviceToolKitInstance.toBleCommand(jsoncmd as any);
    sendCommand({ value }).then((res) => {
      this.resetOta();
    });
  }
  /**
   * ota升级强制退出
   */
  quitOTA(errorString = "") {
    // log.info('ota失败日志', errorString);
    console.log("ota失败日志", errorString);
    const errorMap = {
      packageError: "总包错误",
      packageNumError: "包号错误",
      checkedError: "校验错误",
      dataLengthError: "数据总长度错误",
      dataCRCError: "数据总数CRC错误",
      updateTimeOut: "数据更新超时",
    };
    let jsoncmd = {
      commandType: "OTAQuit",
    };
    //@ts-ignore
    const value = deviceToolKitInstance.toBleCommand(jsoncmd as any);
    sendCommand({ value })
      .then((res) => {
        this.resetOta();
        // this.showError(errorMap[errorString] || tipMap[errorString] || '发生错误')
      })
      .catch((err) => {
        if (!this.state.hadShowError) {
          this.setState({
            hadShowError: true,
          });
          // log.info('ota失败日志', '发送日志OTAQuit失败', err);
          console.info("ota失败日志", "发送日志OTAQuit失败", err);
          if (err.errCode === 10000) {
            let isDisconnect = getStorageSync("isDisconnectUpdate");
            if (isDisconnect) {
              if (this.$checkTimer) clearInterval(this.$checkTimer);
            }
          }
        }
      });
    setTimeout(() => {
      this.errorFun();
    }, 1000);
  }

  /**
   * 处理返回的数据  OTA用
   */
  async parseData(json) {
    console.log("parseData json.commandType", json.commandType);
    if (!json || !json.commandType) return;
    switch (json.commandType) {
      case "OTAStart":
        if (json.responseStatus == "OK") {
          const otaData = await this.getUpgradeData();
          this.$otaDataGroup = {
            ...this.$otaDataGroup,
            otaData,
          };
          this.$otaDataGroup.otaCurrentPackageIndex = 0;
          this.preOTA();
        } else {
          this.quitOTA(json.responseStatus);
        }
        break;
      case "OTAPrepare":
        if (json.responseStatus == "OK") {
          this.processOTA(0, this.$otaDataGroup.otaData[0]);
        } else {
          this.quitOTA(json.responseStatus);
        }
        break;
      case "OTAUpdating":
        if (json.responseStatus == "OK") {
          let ota = this.$otaDataGroup;
          let progressbar =
            (ota.otaCurrentPackageIndex / ota.packageCount) * 100;
          this.setState({
            progressbar: (progressbar <= 1 ? 1 : progressbar).toFixed(0),
          });
          if (!json.currentPackageNo) {
            return;
          }
          console.log(
            "json.currentPackageNo",
            json.currentPackageNo,
            this.$otaDataGroup.packageCount
          );
          if (json.currentPackageNo < this.$otaDataGroup.packageCount) {
            this.$otaDataGroup.otaCurrentPackageIndex++;
            this.processOTA(
              this.$otaDataGroup.otaCurrentPackageIndex,
              this.$otaDataGroup.otaData[
                this.$otaDataGroup.otaCurrentPackageIndex
              ]
            );
          } else {
            this.finishedOTA();
          }
        } else {
          this.quitOTA(json.responseStatus);
        }
        break;
      case "OTAUpdateFinish":
        console.log("完成OTA传输");
        this.setState({
          progressbar: 100,
        });
        this.finishFun();
        // quitOTA()
        break;
      default:
        break;
    }
  }
  /**
   * 从后端拉取固件包，并初始化ota流程的所需对象
   */
  getDeviceUpgrade = async () => {
    let res: any = await InstrumentInfo.getUpgrade({
      instrumentId: this.state.currentDevice.id,
      isWe200: false,
    });
    if (res.data.data == "解析失败") {
      // this.showError('文件解析失败');
      return;
    }
    if (res.data.code !== 200) {
      return;
    }
    const otaHexString = res.data.data;
    const otaBin = string2buffer(res.data.data);
    const packageLength = otaBin?.byteLength || 0;
    const packageSize = this.$otaDataGroup.packageSize;
    const packageCrc8 = Stringkit.getCrc8CodeByString(otaHexString);
    const packageCount = Math.ceil(packageLength / packageSize);
    let { iotVersion: versionNo } = this.state.currentDevice;
    this.$otaDataGroup = {
      ...this.$otaDataGroup,
      otaHexString,
      otaBin,
      packageLength,
      packageSize,
      packageCrc8,
      packageCount,
      versionNo,
    };
    console.log("this.$otaDataGroup ", this.$otaDataGroup);
  };

  notifyBLECharacteristicValueChange = () => {
    const bluetoothInfo = this.props.bluetoothInfo;
    notifyBLECharacteristicValueChange({
      deviceId: bluetoothInfo.deviceId,
      servicesuuid: bluetoothInfo.servicesuuid,
      characteristicsuuid1: bluetoothInfo.characteristicsuuid1,
      characteristicsuuid0: bluetoothInfo.characteristicsuuid0,
    }).then((res) => {
      Taro.onBLECharacteristicValueChange((value) => {
        // let str = ab2hex(value.value); //转为16进制字符串
        //  console.log('返回',str)
        const jsonStatus: any = deviceToolKitInstance.toJsonStatus(value.value);
        log.info("OTA页面设备响应数据打印==》", JSON.stringify(jsonStatus));
        console.info("onBLECharacteristicValueChange json => ", jsonStatus);

        this.$otaDataGroup.currentPackageNo = jsonStatus.currentPackageNo;
        this.$otaDataGroup.countDown = 7;
        this.parseData(jsonStatus);
      });
      setTimeout(() => {
        this.startOTA();
      }, 500);
    });
  };

  createTimer() {
    log.info("设备ota计时器创建成功");
    this.$checkTimer = setInterval(() => {
      // 超过7s没有回包, 直接断开
      if (this.$otaDataGroup.countDown <= 0 && this.state.hadStartOta) {
        this.quitOTA("shutDownMaskTip");
      } else {
        this.$otaDataGroup.countDown--;
      }
      console.log(this.$otaDataGroup.countDown);
    }, 1000);
  }

  //升级销毁页面时关闭小程序蓝牙
  onUnload() {
    console.log("onUnload");
    if (this.$checkTimer) clearInterval(this.$checkTimer);
    Taro.closeBluetoothAdapter();
  }

  onPullDownRefresh() {
    Taro.stopPullDownRefresh();
  }

  onClickStop = (e) => {
    e.stopPropagation();
  };

  // 错误关闭回调
  errorFun = () => {
    this.resetOta();
    this.props.errorFun();
  };
  // 升级完成回调
  finishFun = () => {
    this.props.finishFun();
  };

  render() {
    let { isShow } = this.props;
    let { progressbar } = this.state;
    return (
      <Block>
        <PageMeta pageStyle={isShow ? "overflow: hidden;" : ""} />
        <Popup
          show={isShow}
          closeOnClickOverlay={false}
          round
          overlayStyle="width: 100vw;padding: 0;"
          onClick={this.onClickStop}
        >
          <View
            className={classnames(
              "common-box",
              "common-progress-box",
              "common-large"
            )}
            catchMove
          >
            <View className={classnames("common-popup-title", "margin-samll")}>
              设备升级中
            </View>
            <View className="common-popup-content-box">
              <View className={classnames("common-popup-content", "text-left")}>
                <View className="progress">
                  <Progress
                    percentage={progressbar}
                    strokeWidth="12"
                    color="linearGradient(to right, #eecda1, #ffe9c7) !important"
                  />
                  <View className="percent"> {progressbar}%</View>
                </View>
                <View className="progress-tips">注意事项：</View>
                <View className="progress-tips">1.保持设备开机状态</View>
                <View className="progress-tips">2.请勿切出该页面</View>
              </View>
            </View>
          </View>
        </Popup>
      </Block>
    );
  }
}

const mapStateToProps = (state) => ({
  bluetoothInfo: state.deviceInfo.bluetoothInfo,
});
const mapDispatchToProps = (dispatch) => ({});
export default connect(mapStateToProps, mapDispatchToProps)(UpdateIotFR200);
