import { OneBotAction } from '@/napcat-onebot/action/OneBotAction';
import { ActionName } from '@/napcat-onebot/action/router';
import fs from 'fs';
import { join as joinPath } from 'node:path';
import { calculateFileMD5, uriToLocalFile } from 'napcat-common/src/file';
import { randomUUID } from 'crypto';
import { Static, Type } from '@sinclair/typebox';
import { GoCQHTTPActionsExamples } from '../example/GoCQHTTPActionsExamples';

const PayloadSchema = Type.Object({
  url: Type.Optional(Type.String({ description: '下载链接' })),
  base64: Type.Optional(Type.String({ description: 'base64数据' })),
  name: Type.Optional(Type.String({ description: '文件名' })),
  headers: Type.Optional(Type.Union([Type.String(), Type.Array(Type.String())], { description: '请求头' })),
});

type PayloadType = Static<typeof PayloadSchema>;

const ReturnSchema = Type.Object({
  file: Type.String({ description: '文件路径' }),
}, { description: '下载结果' });

type ReturnType = Static<typeof ReturnSchema>;

export default class GoCQHTTPDownloadFile extends OneBotAction<PayloadType, ReturnType> {
  override actionName = ActionName.GoCQHTTP_DownloadFile;
  override payloadSchema = PayloadSchema;
  override returnSchema = ReturnSchema;
  override actionSummary = '下载文件';
  override actionDescription = '下载网络文件到本地临时目录';
  override actionTags = ['Go-CQHTTP'];
  override payloadExample = GoCQHTTPActionsExamples.DownloadFile.payload;
  override returnExample = GoCQHTTPActionsExamples.DownloadFile.response;

  async _handle (payload: PayloadType): Promise<ReturnType> {
    const isRandomName = !payload.name;
    const name = payload.name || randomUUID();
    let result: Awaited<globalThis.ReturnType<typeof uriToLocalFile>>;

    if (payload.base64) {
      result = await uriToLocalFile(this.core.NapCatTempPath, `base64://${payload.base64}`, name);
    } else if (payload.url) {
      const headers = this.getHeaders(payload.headers);
      result = await uriToLocalFile(this.core.NapCatTempPath, payload.url, name, headers);
    } else {
      throw new Error('不存在任何文件, 无法下载');
    }
    if (!result.success) {
      throw new Error(result.errMsg);
    }
    const filePath = result.path;
    if (fs.existsSync(filePath)) {
      if (isRandomName) {
        // 默认实现要名称未填写时文件名为文件 md5
        const md5 = await calculateFileMD5(filePath);
        const newPath = joinPath(this.core.NapCatTempPath, md5);
        fs.renameSync(filePath, newPath);
        return { file: newPath };
      }
      return { file: filePath };
    } else {
      throw new Error('文件写入失败, 检查权限');
    }
  }

  getHeaders (headersIn?: string | string[]): Record<string, string> {
    const headers: Record<string, string> = {};
    if (typeof headersIn === 'string') {
      headersIn = headersIn.split('[\\r\\n]');
    }
    if (Array.isArray(headersIn)) {
      for (const headerItem of headersIn) {
        const spilt = headerItem.indexOf('=');
        if (spilt < 0) {
          headers[headerItem] = '';
        } else {
          const key = headerItem.substring(0, spilt);
          headers[key] = headerItem.substring(spilt + 1);
        }
      }
    }
    if (!headers['Content-Type']) {
      headers['Content-Type'] = 'application/octet-stream';
    }
    return headers;
  }
}
