import { callNTQQApi, GeneralCallResult, NTQQApiClass, NTQQApiMethod } from '../ntcall'
import { Group, SelfInfo, User } from '../types'
import { ReceiveCmdS } from '../hook'
import { selfInfo, uidMaps } from '../../common/data'
import { NTQQWindowApi, NTQQWindows } from './window'
import { cacheFunc, isQQ998, log, sleep } from '../../common/utils'
import { wrapperApi } from '@/ntqqapi/native/wrapper'
import * as https from 'https'
import { RequestUtil } from '@/common/utils/request'

let userInfoCache: Record<string, User> = {} // uid: User

export interface ClientKeyData extends GeneralCallResult {
  url: string;
  keyIndex: string;
  clientKey: string;
  expireTime: string;
}

export class NTQQUserApi {
  static async setQQAvatar(filePath: string) {
    return await callNTQQApi<GeneralCallResult>({
      methodName: NTQQApiMethod.SET_QQ_AVATAR,
      args: [
        {
          path: filePath,
        },
        null,
      ],
      timeoutSecond: 10, // 10秒不一定够
    })
  }

  static async getSelfInfo() {
    return await callNTQQApi<SelfInfo>({
      className: NTQQApiClass.GLOBAL_DATA,
      methodName: NTQQApiMethod.SELF_INFO,
      timeoutSecond: 2,
    })
  }

  static async getUserInfo(uid: string) {
    const result = await callNTQQApi<{ profiles: Map<string, User> }>({
      methodName: NTQQApiMethod.USER_INFO,
      args: [{ force: true, uids: [uid] }, undefined],
      cbCmd: ReceiveCmdS.USER_INFO,
    })
    return result.profiles.get(uid)
  }

  static async getUserDetailInfo(uid: string, getLevel = false) {
    // this.getUserInfo(uid);
    let methodName = !isQQ998 ? NTQQApiMethod.USER_DETAIL_INFO : NTQQApiMethod.USER_DETAIL_INFO_WITH_BIZ_INFO
    const fetchInfo = async () => {
      const result = await callNTQQApi<{ info: User }>({
        methodName,
        cbCmd: ReceiveCmdS.USER_DETAIL_INFO,
        afterFirstCmd: false,
        cmdCB: (payload) => {
          const success = payload.info.uid == uid
          // log("get user detail info", success, uid, payload)
          return success
        },
        args: [
          {
            uid,
          },
          null,
        ],
      })
      const info = result.info
      if (info?.uin) {
        uidMaps[info.uid] = info.uin
      }
      return info
    }
    // 首次请求两次才能拿到的等级信息
    if (!userInfoCache[uid] && getLevel) {
      await fetchInfo()
      await sleep(1000)
    }
    let userInfo = await fetchInfo()
    userInfoCache[uid] = userInfo
    return userInfo
  }

  // return 'p_uin=o0xxx; p_skey=orXDssiGF8axxxxxxxxxxxxxx_; skey='
  static async getCookieWithoutSkey() {
    return await callNTQQApi<string>({
      className: NTQQApiClass.GROUP_HOME_WORK,
      methodName: NTQQApiMethod.UPDATE_SKEY,
      args: [
        {
          domain: 'qun.qq.com',
        },
      ],
    })
  }
  static async getQzoneCookies() {
    const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + selfInfo.uin + '&clientkey=' + this.getClientKey() + '&u1=https%3A%2F%2Fuser.qzone.qq.com%2F' + selfInfo.uin + '%2Finfocenter&keyindex=19%27'
    let cookies: { [key: string]: string; } = {};
    try {
      cookies = await RequestUtil.HttpsGetCookies(requestUrl);
    } catch (e: any) {
      cookies = {}
    }
    return cookies;
  }
  static async getSkey(): Promise<string> {
    const clientKeyData = await this.getClientKey()
    if (clientKeyData.result !== 0) {
      throw new Error('获取clientKey失败')
    }
    const url = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + selfInfo.uin
      + '&clientkey=' + clientKeyData.clientKey
      + '&u1=https%3A%2F%2Fh5.qzone.qq.com%2Fqqnt%2Fqzoneinpcqq%2Ffriend%3Frefresh%3D0%26clientuin%3D0%26darkMode%3D0&keyindex=' + clientKeyData.keyIndex;
    return (await RequestUtil.HttpsGetCookies(url))?.skey;
  }

  @cacheFunc(60 * 30 * 1000)
  static async getCookies(domain: string) {
    const skey = await this.getSkey();
    const pskey = (await this.getPSkey([domain])).get(domain);
    if (!pskey || !skey) {
      throw new Error('获取Cookies失败')
    }
    const bkn = NTQQUserApi.genBkn(skey)
    const cookies = `p_skey=${pskey}; skey=${skey}; p_uin=o${selfInfo.uin}; uin=o${selfInfo.uin}`;
    return { cookies, bkn }
  }

  static genBkn(sKey: string) {
    sKey = sKey || ''
    let hash = 5381

    for (let i = 0; i < sKey.length; i++) {
      const code = sKey.charCodeAt(i)
      hash = hash + (hash << 5) + code
    }

    return (hash & 0x7fffffff).toString()
  }

  static async getPSkey(domains: string[]): Promise<Map<string, string>> {
    const res = await wrapperApi.NodeIQQNTWrapperSession.getTipOffService().getPskey(domains, true)
    if (res.result !== 0) {
      throw new Error(`获取Pskey失败: ${res.errMsg}`)
    }
    return res.domainPskeyMap
  }

  static async getClientKey(): Promise<ClientKeyData> {
    return await wrapperApi.NodeIQQNTWrapperSession.getTicketService().forceFetchClientKey('')
  }

}