import { GeneralCallResult, InstanceContext, NapCatCore } from '@/napcat-core';
import {
  createFlashTransferResult,
  FileListResponse,
  FlashFileSetInfo,
  SendStatus,
  UploadSceneType,
} from '@/napcat-core/data/flash';
import { Peer } from '@/napcat-core/types';

export class NTQQFlashApi {
  context: InstanceContext;
  core: NapCatCore;

  constructor (context: InstanceContext, core: NapCatCore) {
    this.context = context;
    this.core = core;
  }

  /**
   * 发起闪传上传任务
   * @param fileListToUpload 上传文件绝对路径的列表，可以是文件夹！！
   * @param thumbnailPath
   * @param filesetName
   */
  async createFlashTransferUploadTask (fileListToUpload: string[], thumbnailPath: string, filesetName: string): Promise<GeneralCallResult & {
    createFlashTransferResult: createFlashTransferResult;
    seq: number;
  }> {
    const flashService = this.context.session.getFlashTransferService();

    const timestamp: number = Date.now();
    const selfInfo = this.core.selfInfo;

    const fileUploadArg = {
      screen: 1, // 1
      name: filesetName,
      uploaders: [{
        uin: selfInfo.uin,
        uid: selfInfo.uid,
        sendEntrance: '',
        nickname: selfInfo.nick,
      }],
      coverPath: thumbnailPath,
      paths: fileListToUpload,
      excludePaths: [],
      expireLeftTime: 0,
      isNeedDelDeviceInfo: false,
      isNeedDelLocation: false,
      coverOriginalInfos: [
        {
          path: fileListToUpload[0] || '',
          thumbnailPath,
        },
      ],
      uploadSceneType: UploadSceneType.KUPLOADSCENEAIOFILESELECTOR, // 不知道怎么枚举 先硬编码吧 (PC QQ 10)
      detectPrivacyInfoResult: {
        exists: false,
        allDetectResults: new Map(),
      },
    };

    const uploadResult = await flashService.createFlashTransferUploadTask(timestamp, fileUploadArg);
    if (uploadResult.result === 0) {
      this.context.logger.log('[Flash] 发起闪传任务成功');
      return uploadResult;
    } else {
      this.context.logger.logError('[Flash] 发起闪传上传任务失败！！');
      return uploadResult;
    }
  }

  /**
   * 下载闪传文件集
   * @param fileSetId
   */
  async downloadFileSetBySetId (fileSetId: string): Promise<GeneralCallResult & {
    extraInfo: unknown;
  }> {
    const flashService = this.context.session.getFlashTransferService();

    const result = await flashService.startFileSetDownload(fileSetId, 1, { isIncludeCompressInnerFiles: false });  // 为了方便，暂时硬编码
    if (result.result === 0) {
      this.context.logger.log('[Flash] 成功开始下载文件集');
    } else {
      this.context.logger.logError('[Flash] 尝试下载文件集失败！');
    }
    return result;
  }

  /**
   * 获取闪传的外链分享
   * @param fileSetId
   */
  async getShareLinkBySetId (fileSetId: string): Promise<GeneralCallResult & {
    shareLink: string;
    expireTimestamp: string;
  }> {
    const flashService = this.context.session.getFlashTransferService();

    const result = await flashService.getShareLinkReq(fileSetId);
    if (result.result === 0) {
      this.context.logger.log('[Flash] 获取闪传外链分享成功:', result.shareLink);
    } else {
      this.context.logger.logError('[Flash] 获取闪传外链失败！！');
    }
    return result;
  }

  /**
   * 从分享外链获取文件集id
   * @param shareCode
   */
  async fromShareLinkFindSetId (shareCode: string): Promise<GeneralCallResult & {
    fileSetId: string;
  }> {
    const flashService = this.context.session.getFlashTransferService();

    const result = await flashService.getFileSetIdByCode(shareCode);
    if (result.result === 0) {
      this.context.logger.log('[Flash] 获取shareCode的文件集Id成功！');
    } else {
      this.context.logger.logError('[Flash] 获取文件集ID失败！！');
    }
    return result;
  }

  /**
   * 获取fileSet的文件结构信息  （未来可能需要深度遍历）
   * == 注意返回结构和其它的不同，没有GeneralCallResult!!! ==
   * @param fileSetId
   */
  async getFileListBySetId (fileSetId: string): Promise<FileListResponse> {
    const flashService = this.context.session.getFlashTransferService();

    const requestArg = {
      seq: 0,
      fileSetId,
      isUseCache: false,
      sceneType: 1,  // 硬编码
      reqInfos: [
        {
          count: 18, // 18 ??
          paginationInfo: {},
          parentId: '',
          reqIndexPath: '',
          reqDepth: 1,
          filterCondition: {
            fileCategory: 0,
            filterType: 0,
          },
          sortConditions: [
            {
              sortField: 0,
              sortOrder: 0,
            },
          ],
          isNeedPhysicalInfoReady: false,
        },
      ],
    };
    const result = await flashService.getFileList(requestArg);
    if (result.rsp.result === 0) {
      this.context.logger.log('[Flash] 获取fileSet文件信息成功！');
      return result.rsp;
    } else {
      this.context.logger.logError(`[Flash] 获取文件信息失败：ErrMsg: ${result.rsp.errMs}`);
      return result.rsp;
    }
  }

  /**
   * 获取闪传文件集合信息
   * @param fileSetId
   */
  async getFileSetIndoBySetId (fileSetId: string): Promise<GeneralCallResult & {
    seq: number;
    isCache: boolean;
    fileSet: FlashFileSetInfo;
  }> {
    const flashService = this.context.session.getFlashTransferService();

    const requestArg = {
      fileSetId,
    };

    const result = await flashService.getFileSet(requestArg);
    if (result.result === 0) {
      this.context.logger.log('[Flash] 获取闪传文件集信息成功！');
    } else {
      this.context.logger.logError('[Flash] 获取闪传文件信息失败！！');
    }
    return result;
  }

  /**
   * 发送闪传消息（私聊/群聊）
   * @param fileSetId
   * @param peer
   */
  async sendFlashMessage (fileSetId: string, peer: Peer): Promise<{
    errCode: number,
    errMsg: string,
    rsp: {
      sendStatus: SendStatus[];
    };
  }> {
    const flashService = this.context.session.getFlashTransferService();

    const target = {
      destUid: peer.peerUid,
      destType: peer.chatType,
      // destUin: peer.peerUin,
    };

    const requestsArg = {
      fileSetId,
      targets: [target],
    };

    const result = await flashService.sendFlashTransferMsg(requestsArg);
    if (result.errCode === 0) {
      this.context.logger.log('[Flash] 消息发送成功');
    } else {
      this.context.logger.logError(`[Flash] 消息发送失败！！原因：${result.errMsg}`);
    }
    return result;
  }

  /**
   * 获取闪传文件集中某个文件的下载URL（外链）
   * @param fileSetId
   * @param options
   */
  async getFileTransUrl (fileSetId: string, options: { fileName?: string; fileIndex?: number; }): Promise<GeneralCallResult & {
    transferUrl: string;
  }> {
    const flashService = this.context.session.getFlashTransferService();
    const result = await this.getFileListBySetId(fileSetId);

    const { fileName, fileIndex } = options;

    let targetFile: any;
    let file: any;

    const allFolder = result.fileLists;

    // eslint-disable-next-line no-labels
    searchLoop: for (const folder of allFolder) {
      const fileList = folder.fileList;
      for (let i = 0; i < fileList.length; i++) {
        file = fileList[i];

        if (fileName !== undefined && file.name === fileName) {
          targetFile = file;
          // eslint-disable-next-line no-labels
          break searchLoop;
        }

        if (fileIndex !== undefined && i === fileIndex) {
          targetFile = file;
          // eslint-disable-next-line no-labels
          break searchLoop;
        }
      }
    }
    if (targetFile === undefined) {
      this.context.logger.logError('[Flash] 未找到对应文件！！');
      return {
        result: -1,
        errMsg: '未找到对应文件',
        transferUrl: '',
      };
    } else {
      this.context.logger.log('[Flash] 找到对应文件，准备尝试获取传输链接');
      const res = await flashService.startFileTransferUrl(targetFile);
      return {
        result: 0,
        errMsg: '',
        transferUrl: res.url,
      };
    }
  }

  async createFileThumbnail (filePath: string): Promise<any> {
    const msgService = this.context.session.getMsgService();
    const savePath = msgService.getFileThumbSavePathForSend(750, true);

    const result = await this.core.util.createThumbnailImage(
      'flashtransfer',
      filePath,
      savePath,
      {
        width: 520,
        height: 520,
      },
      'jpeg',
      null
    );
    if (result.result === 0) {
      this.context.logger.log('获取缩略图成功！！');
      result.targetPath = savePath;
      return result;
    }
    return result;
  }
}
