import { ref } from 'vue';
import { onLoad, onUnload } from '@dcloudio/uni-app';
import {
  getReadWriteStandard,
  getSakHex,
  getSakType,
  parseAtqa,
  transformArrayBuffer,
} from './utils';

export default function useNFCMpWeiXin(
  listener: (data: NFC.Result) => void,
  options: { timeout?: number; checkConnectedDelay?: number } = {
    timeout: 0,
    checkConnectedDelay: 500,
  },
) {
  /** 是否支持 nfc */
  const isSupportNFC = ref<boolean | undefined>(false);
  /** 是否监听中 */
  const isListening = ref<boolean>(false);
  /**
   * 是否已连接
   * 需要手动维护，调用connect()后连接 调用close()后断开 ,实际nfc 断开之后是无法监听到的， isConnected 已经被废弃掉了
   */
  const isConnected = ref<boolean>(false);
  /** nfc 数据 */
  const data = ref<NFC.Result>({
    id: new ArrayBuffer(0),
    techs: [],
    byteArray: [],
    hexArray: [],
    hexNumberArray: [],
    hexString: '',
  });

  /** nfc 适配器 */
  let nfcAdapter: NFC.Adapter;

  /** nfc 实例 */
  let nfcInstance: NFC.Instance | undefined;

  /** ndef 写入方式比较特殊，需要特殊处理 */
  let isNdef = ref(false);

  /**
   * 初始化 nfc adapter
   *
   * @return {*}
   */
  async function initNfcAdapter() {
    await checkHCEState();

    if (!isSupportNFC.value) return;

    nfcAdapter = wx.getNFCAdapter();

    nfcAdapter.onDiscovered(innerListener);
  }

  function getAtqa(nfcInstance: NFC.Instance): Promise<NFC.Atqa> {
    return new Promise((resolve, reject) => {
      if (!nfcInstance.getAtqa) {
        reject({ errMsg: '不支持获取 atqa' });
      }
      nfcInstance?.getAtqa?.({
        success: (res) => {
          resolve(res);
        },
        fail: (err) => {
          reject(err);
        },
      });
    });
  }

  function getMaxTransceiveLength(
    nfcInstance: NFC.Instance,
  ): Promise<NFC.MaxTransceiveLength> {
    return new Promise((resolve, reject) => {
      if (!nfcInstance.getMaxTransceiveLength) {
        reject({ errMsg: '不支持获取 maxTransceiveLength' });
      }
      nfcInstance?.getMaxTransceiveLength?.({
        success: (res) => {
          resolve(res);
        },
        fail: (err) => {
          reject(err);
        },
      });
    });
  }

  function getSak(nfcInstance: NFC.Instance): Promise<NFC.Sak> {
    return new Promise((resolve, reject) => {
      if (!nfcInstance.getMaxTransceiveLength) {
        reject({ errMsg: '不支持获取 sak' });
      }

      nfcInstance?.getSak?.({
        success: (res) => {
          resolve(res);
        },
        fail: (err) => {
          reject(err);
        },
      });
    });
  }

  /**
   * 检查HCE状态
   *
   * @return {*}
   */
  function checkHCEState() {
    // uni.showToast({ title: '初始化 NFC' });
    return new Promise((resolve, reject) => {
      wx.getHCEState({
        success: (res: any) => {
          isSupportNFC.value = true;
          resolve(res);
        },
        fail: (err: any) => {
          isSupportNFC.value = false;
          reject(err);
        },
      });
    });
  }

  /**
   * 启用HCE
   *
   * @return {*}
   */
  function startHCE() {
    if (!isSupportNFC.value) {
      uni.showToast({
        title: '设备不支持 NFC',
        icon: 'none',
      });
      return;
    }

    // 前置校验
    if (!nfcAdapter) {
      uni.showToast({ title: '请先初始化 NFC 适配器', icon: 'none' });
      return false;
    }

    if (isListening.value) {
      uni.showToast({ title: 'NFC 监听已开启，无需重复操作', icon: 'none' });
      return true;
    }
    nfcAdapter.startDiscovery();
    isListening.value = true;
    uni.showToast({
      title: '开始监听NFC',
      icon: 'none',
    });
  }

  /**
   * 停用HCE
   *
   * @return {*}
   */
  function stopHCE() {
    // 前置校验
    if (!isSupportNFC.value) {
      uni.showToast({
        title: '设备不支持 NFC',
        icon: 'none',
      });
      return;
    }

    // 前置校验
    if (!nfcAdapter) {
      uni.showToast({ title: '请先初始化 NFC 适配器', icon: 'none' });
      return false;
    }

    if (!isListening.value) {
      uni.showToast({ title: 'NFC 监听已关闭，无需重复操作', icon: 'none' });
      return true;
    }

    nfcAdapter.stopDiscovery();
    isListening.value = false;
    uni.showToast({
      title: '停止监听NFC',
      icon: 'none',
    });
  }

  /**
   * 读取监听
   *
   * @param {*} res
   */
  async function innerListener(res: NFC.Data) {
    const transform = transformArrayBuffer(res?.id);

    /**
     * 获取标签类型
     * 默认取第一个
     */
    const type = res.techs[0];

    switch (type) {
      case 'NFC-A':
        nfcInstance = nfcAdapter.getNfcA();
        break;
      case 'NFC-B':
        nfcInstance = nfcAdapter.getNfcB();
        break;
      case 'NFC-F':
        nfcInstance = nfcAdapter.getNfcF();
        break;
      case 'NFC-V':
        nfcInstance = nfcAdapter.getNfcV();
        break;
      case 'MIFARE Classic':
        nfcInstance = nfcAdapter.getMifareClassic();
        break;
      case 'MIFARE Ultralight':
        nfcInstance = nfcAdapter.getMifareUltralight();
        break;
      case 'Ndef':
        isNdef.value = true;
        nfcInstance = nfcAdapter.getNdef();
        break;
      case 'ISO-DEP':
        nfcInstance = nfcAdapter.getIsoDep();
        break;
      default:
        nfcInstance = undefined;
        break;
    }

    if (res.techs.includes('NFC-A')) {
      const nfcA = nfcAdapter.getNfcA();
      try {
        const atqa = await getAtqa(nfcA);
        const atqaInfo = parseAtqa(atqa.atqa);
        data.value.atqa = atqa.atqa;
        data.value.uidType = atqaInfo?.uidType;
        data.value.storageSize = atqaInfo?.storageSize;
        data.value.manufacturer = atqaInfo?.manufacturer;
        data.value.cardFeatures = atqaInfo?.cardFeatures;
        data.value.reserved = atqaInfo?.reserved;
      } catch (error) {}

      try {
        const sak = await getSak(nfcA);
        const sakType = getSakType(sak.sak);
        const sakHex = getSakHex(sak.sak);
        data.value.sak = sak.sak;
        data.value.sakType = sakType;
        data.value.sakHex = sakHex;
      } catch (error) {}
    }

    if (nfcInstance) {
      const maxTransceive = await getMaxTransceiveLength(nfcInstance);
      data.value.maxTransceiveLength = maxTransceive.length;

      data.value.readWriteStandard = getReadWriteStandard(res.techs);

      if (options?.timeout && options.timeout > 0) {
        nfcInstance?.setTimeout?.({
          timeout: options.timeout,
        });
      }

      data.value = {
        ...data.value,
        ...res,
        ...transform,
      };

      isConnected.value = true;

      listener?.(data.value);
      // 可将改行去除
      uni?.__dev_tool_nfc_collection__?.(data.value);
    }
  }

  /**
   * 移除监听读取消息
   *
   * @return {*}
   */
  function offHCEMessage() {
    if (!isSupportNFC.value) {
      uni.showToast({ title: '设备不支持 NFC，无需移除监听', icon: 'none' });
      return { errMsg: 'success' };
    }
    isConnected.value = false;
    nfcAdapter.offDiscovered(innerListener);

    uni.showToast({ title: 'NFC 监听已移除', icon: 'none' });
    return { errMsg: 'success' };
  }

  /**
   * 连接 nfc
   *
   * @return {*}
   */
  function connect() {
    return new Promise((resolve, reject) => {
      if (!isSupportNFC.value) {
        uni.showToast({ title: '设备不支持 NFC', icon: 'none' });
        reject({
          errMsg: '设备不支持 NFC',
        });
        return;
      }

      if (!isListening.value) {
        uni.showToast({ title: '请先开启前台调度监听', icon: 'none' });
        reject({
          errMsg: '请先开启前台调度监听',
        });
        return;
      }

      if (!nfcInstance) {
        uni.showToast({ title: '请先靠近 NFC 标签', icon: 'none' });
        reject({
          errMsg: '请先靠近 NFC 标签',
        });
        return;
      }

      nfcInstance?.connect?.({
        success: (res) => {
          console.log('res: ', res);
          resolve(res);
          isConnected.value = true;
          uni.showToast({
            title: 'NFC 连接成功',
            icon: 'none',
          });
        },
        fail: (err) => {
          if (err.errMsg === 'connect:fail:Tech already connected') {
            resolve(err);
            isConnected.value = true;
          } else {
            reject(err);
            isConnected.value = false;
            uni.showToast({
              title: 'NFC 连接失败',
              icon: 'none',
            });
          }
        },
      });
    });
  }

  /**
   * 断开 nfc
   *
   * @return {*}
   */
  function close() {
    return new Promise((resolve, reject) => {
      if (!isSupportNFC.value) {
        reject({
          errMsg: '不支持NFC',
        });
        return;
      }

      if (!nfcInstance) {
        reject({
          errMsg: '未读取到NFC卡',
        });
        return;
      }

      nfcInstance?.close?.({
        success: (res) => {
          isConnected.value = false;
          nfcInstance = undefined;
          resolve(res);

          uni.showToast({ title: 'NFC 连接已关闭', icon: 'none' });
        },
        fail: (err) => {
          reject(err);
          uni.showToast({ title: 'NFC 连接关闭失败', icon: 'none' });
        },
      });
    });
  }

  async function transceive(data: ArrayBuffer) {
    return new Promise((resolve, reject) => {
      if (!isSupportNFC.value) {
        reject({
          errMsg: '不支持NFC',
        });
        return;
      }

      if (!nfcInstance) {
        reject({
          errMsg: '未读取到NFC卡',
        });
        return;
      }
      nfcInstance?.transceive?.({
        data,
        success: (res) => {
          resolve(res);
        },
        fail: (err) => {
          reject(err);
        },
      });
    });
  }

  async function writeNdefMessage(data: NFC.NdefData) {
    return new Promise((resolve, reject) => {
      if (!isSupportNFC.value) {
        reject({
          errMsg: '不支持NFC',
        });
        return;
      }

      if (!nfcInstance) {
        reject({
          errMsg: '未读取到NFC卡',
        });
        return;
      }
      nfcInstance?.writeNdefMessage?.({
        ...data,
        success: (res) => {
          resolve(res);
        },
        fail: (err) => {
          reject(err);
        },
      });
    });
  }

  /**
   * 写入数据
   *
   * 支持以以下类型
   * ISO-DEP
   * MIFARE Classic
   * MIFARE Ultralight
   * NFC-A
   * NFC-B
   * NFC-F
   * NFC-V
   *
   * @param {*} data
   * @return {*}
   */
  async function write(data: ArrayBuffer) {
    try {
      // 连接 nfc
      await connect();
      uni.showToast({
        title: '开始写入数据, 请勿断开连接',
        icon: 'none',
      });
      // 写入数据

      await transceive(data);

      uni.showToast({
        title: '写入成功',
        icon: 'none',
      });
      // 断开 nfc
      // await close();
    } catch (error) {
      throw error;
    }
  }

  /**
   * 写入数据
   * 支持以以下类型
   * Ndef
   *
   * @param {NFC.NdefData} data
   */
  async function writeNdf(data: NFC.NdefData) {
    try {
      // 连接 nfc
      await connect();
      uni.showToast({
        title: '开始写入数据, 请勿断开连接',
        icon: 'none',
      });
      // 写入数据

      await writeNdefMessage(data);

      uni.showToast({
        title: '写入成功',
        icon: 'none',
      });
      // 断开 nfc
      await close();
    } catch (error) {
      throw error;
    }
  }

  onLoad(() => {
    initNfcAdapter();
  });

  onUnload(() => {
    stopHCE();
    offHCEMessage();
  });

  return {
    data,
    isNdef,
    isSupportNFC,
    isListening,
    isConnected,
    nfcInstance,
    startHCE,
    stopHCE,
    connect,
    close,
    write,
    writeNdf,
  };
}
