import request from '@/utils/request';
import Taro from '@tarojs/taro'
import dayjs from 'dayjs';
import crypto from 'crypto-js';
import {Base64} from 'js-base64';
import {FileRecord} from "@/api/system/file/model";
import { TenantId } from "@/config/app";

export async function uploadOssByPath(filePath: string) {
  return new Promise(async (resolve) => {
    const date = new Date();
    date.setMinutes(date.getMinutes() + 1);
    const policyText = {
      expiration: date.toISOString(), // 设置policy过期时间。
      conditions: [
        // 限制上传大小。
        ["content-length-range", 0, 1024 * 1024 * 1024],
      ],
    };
    let sts = Taro.getStorageSync('sts');
    let stsExpired = Taro.getStorageSync('stsExpiredAt');
    if (!sts || (stsExpired && dayjs().isAfter(dayjs(stsExpired)))) {
      // @ts-ignore
      const {data: {data: {credentials}}} = await request.get(`https://gle-server.websoft.top/api/oss/getSTSToken`)
      Taro.setStorageSync('sts', credentials)
      Taro.setStorageSync('stsExpiredAt', credentials.expiration)
      sts = credentials
    }
    console.log(sts)
    const [filename, ext] = filePath.split('.')
    const key = `headers/${filename + (Math.random() * 100000)}.${ext}`
    const policy = Base64.encode(JSON.stringify(policyText))
    const signature = computeSignature(sts.accessKeySecret, policy)
    Taro.uploadFile({
      url: 'https://oss.wsdns.cn',
      name: 'file',
      filePath,
      formData: {
        key,
        policy,
        OSSAccessKeyId: sts.accessKeyId,
        signature,
        'x-oss-security-token': sts.securityToken
      },
      success: () => {
        resolve(`https://oss.wsdns.cn/${key}`)
      }
    })
  })
}

const computeSignature = (accessKeySecret: string, canonicalString: string): string => {
  return crypto.enc.Base64.stringify(crypto.HmacSHA1(canonicalString, accessKeySecret));
}

/**
 * 上传阿里云OSS
 */
export async function uploadFileByPath(filePath: string) {
  const parseResponseToRecord = (res: any): FileRecord => {
    const statusCode = Number(res?.statusCode)
    if (Number.isFinite(statusCode) && statusCode !== 200) {
      throw new Error(`上传失败（HTTP ${statusCode}）`)
    }

    const raw = res?.data
    if (raw === null || raw === undefined || raw === '') {
      throw new Error('上传失败：响应为空')
    }

    let data: any
    if (typeof raw === 'string') {
      const cleaned = raw.replace(/^\uFEFF/, '').trim()
      try {
        data = JSON.parse(cleaned)
      } catch (_e) {
        throw new Error('上传失败：响应格式错误')
      }
    } else {
      data = raw
    }

    if (data?.code === 0) return data.data as FileRecord

    const codeHint = data?.code !== undefined && data?.code !== null ? `（code=${String(data.code)}）` : ''
    let msg = String(data?.message || data?.msg || data?.error || data?.errMsg || `上传失败${codeHint}`)
    try {
      msg = decodeURIComponent(escape(msg))
    } catch (_e) {
      // ignore
    }
    throw new Error(msg || '上传失败')
  }

  const tenantIdInStorage = Taro.getStorageSync('TenantId')
  const tenantId =
    tenantIdInStorage && String(tenantIdInStorage) === String(TenantId)
      ? tenantIdInStorage
      : TenantId

  const header: Record<string, string> = {
    'content-type': 'application/json',
    TenantId: String(tenantId)
  }

  return new Promise((resolve: (result: FileRecord) => void, reject) => {
    if (!filePath) {
      reject(new Error('缺少 filePath'))
      return
    }

    Taro.uploadFile({
      url: 'https://server.websoft.top/api/oss/upload',
      filePath,
      name: 'file',
      header,
      success: (res) => {
        try {
          resolve(parseResponseToRecord(res))
        } catch (e) {
          reject(e)
        }
      },
      fail: (err) => {
        const msg = String((err as any)?.errMsg || (err as any)?.message || '上传请求失败')
        reject(new Error(msg))
      }
    })
  })
}

export async function uploadFile() {
  return new Promise(async (resolve: (result: FileRecord) => void, reject) => {
    Taro.chooseImage({
      count: 1,
      sizeType: ['compressed'],
      sourceType: ['album', 'camera'],
      success: async (res) => {
        const tempFilePath = res.tempFilePaths[0];
        try {
          const record = await uploadFileByPath(tempFilePath)
          resolve(record)
        } catch (e) {
          reject(e)
        }
      },
      fail: (err) => {
        console.log('选择图片失败', err);
        reject(new Error('选择图片失败'))
      }
    });
  })

}
