/**
 * Toonflow AI供应商模板 - 可灵AI
 * @version 2.0
 */

// ============================================================
// 类型定义
// ============================================================

type VideoMode =
  | "singleImage"
  | "startEndRequired"
  | "endFrameOptional"
  | "startFrameOptional"
  | "text"
  | (`videoReference:${number}` | `imageReference:${number}` | `audioReference:${number}`)[];

interface TextModel {
  name: string;
  modelName: string;
  type: "text";
  think: boolean;
}

interface ImageModel {
  name: string;
  modelName: string;
  type: "image";
  mode: ("text" | "singleImage" | "multiReference")[];
  associationSkills?: string;
}

interface VideoModel {
  name: string;
  modelName: string;
  type: "video";
  mode: VideoMode[];
  associationSkills?: string;
  audio: "optional" | false | true;
  durationResolutionMap: { duration: number[]; resolution: string[] }[];
}

interface TTSModel {
  name: string;
  modelName: string;
  type: "tts";
  voices: { title: string; voice: string }[];
}

interface VendorConfig {
  id: string;
  version: string;
  name: string;
  author: string;
  description?: string;
  icon?: string;
  inputs: { key: string; label: string; type: "text" | "password" | "url"; required: boolean; placeholder?: string }[];
  inputValues: Record<string, string>;
  models: (TextModel | ImageModel | VideoModel | TTSModel)[];
}

type ReferenceList =
  | { type: "image"; sourceType: "base64"; base64: string }
  | { type: "audio"; sourceType: "base64"; base64: string }
  | { type: "video"; sourceType: "base64"; base64: string };

interface ImageConfig {
  prompt: string;
  referenceList?: Extract<ReferenceList, { type: "image" }>[];
  size: "1K" | "2K" | "4K";
  aspectRatio: `${number}:${number}`;
}

interface VideoConfig {
  duration: number;
  resolution: string;
  aspectRatio: "16:9" | "9:16";
  prompt: string;
  referenceList?: ReferenceList[];
  audio?: boolean;
  mode: VideoMode[];
}

interface TTSConfig {
  text: string;
  voice: string;
  speechRate: number;
  pitchRate: number;
  volume: number;
  referenceList?: Extract<ReferenceList, { type: "audio" }>[];
}

interface PollResult {
  completed: boolean;
  data?: string;
  error?: string;
}

// ============================================================
// 全局声明
// ============================================================

declare const axios: any;
declare const logger: (msg: string) => void;
declare const jsonwebtoken: any;
declare const zipImage: (base64: string, size: number) => Promise<string>;
declare const zipImageResolution: (base64: string, w: number, h: number) => Promise<string>;
declare const mergeImages: (base64Arr: string[], maxSize?: string) => Promise<string>;
declare const urlToBase64: (url: string) => Promise<string>;
declare const pollTask: (fn: () => Promise<PollResult>, interval?: number, timeout?: number) => Promise<PollResult>;
declare const createOpenAI: any;
declare const createDeepSeek: any;
declare const createZhipu: any;
declare const createQwen: any;
declare const createAnthropic: any;
declare const createOpenAICompatible: any;
declare const createXai: any;
declare const createMinimax: any;
declare const createGoogleGenerativeAI: any;
declare const exports: {
  vendor: VendorConfig;
  textRequest: (m: TextModel, t: boolean, tl: 0 | 1 | 2 | 3) => any;
  imageRequest: (c: ImageConfig, m: ImageModel) => Promise<string>;
  videoRequest: (c: VideoConfig, m: VideoModel) => Promise<string>;
  ttsRequest: (c: TTSConfig, m: TTSModel) => Promise<string>;
  checkForUpdates?: () => Promise<{ hasUpdate: boolean; latestVersion: string; notice: string }>;
  updateVendor?: () => Promise<string>;
};

// ============================================================
// 供应商配置
// ============================================================

const vendor: VendorConfig = {
  id: "klingai",
  version: "2.0",
  author: "Toonflow",
  name: "可灵AI",
  description:
    "可灵AI视频生成\n\n支持可灵全系列视频模型，包括 kling-video-o1、kling-v3-omni、kling-v3、kling-v2-6、kling-v2-5-turbo、kling-v2-1、kling-v2-master、kling-v1-6、kling-v1-5、kling-v1 等。\n\n需要在[可灵AI开放平台](https://klingai.com)\n\n获取 Access Key 和 Secret Key。",
  inputs: [
    { key: "accessKey", label: "Access Key", type: "password", required: true, placeholder: "请输入可灵AI的Access Key" },
    { key: "secretKey", label: "Secret Key", type: "password", required: true, placeholder: "请输入可灵AI的Secret Key" },
    { key: "baseUrl", label: "请求地址", type: "url", required: true, placeholder: "默认：https://api-beijing.klingai.com" },
  ],
  inputValues: { accessKey: "", secretKey: "", baseUrl: "https://api-beijing.klingai.com" },
  models: [
    // kling-video-o1 (Omni)
    {
      name: "kling-video-o1 标准",
      modelName: "kling-video-o1:std",
      type: "video",
      mode: ["text", "singleImage", "startEndRequired", ["imageReference:7", "videoReference:1"]],
      audio: false,
      durationResolutionMap: [{ duration: [5, 10], resolution: ["720p"] }],
    },
    {
      name: "kling-video-o1 专家",
      modelName: "kling-video-o1:pro",
      type: "video",
      mode: ["text", "singleImage", "startEndRequired", ["imageReference:7", "videoReference:1"]],
      audio: false,
      durationResolutionMap: [{ duration: [5, 10], resolution: ["720p"] }],
    },
    // kling-v3-omni (Omni)
    {
      name: "kling-v3-omni 标准",
      modelName: "kling-v3-omni:std",
      type: "video",
      mode: ["text", "singleImage", "startEndRequired", ["imageReference:7", "videoReference:1"]],
      audio: false,
      durationResolutionMap: [{ duration: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], resolution: ["720p"] }],
    },
    {
      name: "kling-v3-omni 专家",
      modelName: "kling-v3-omni:pro",
      type: "video",
      mode: ["text", "singleImage", "startEndRequired", ["imageReference:7", "videoReference:1"]],
      audio: false,
      durationResolutionMap: [{ duration: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], resolution: ["720p"] }],
    },
    // kling-v3
    {
      name: "kling-v3 标准",
      modelName: "kling-v3:std",
      type: "video",
      mode: ["text", "singleImage", "startEndRequired"],
      audio: false,
      durationResolutionMap: [{ duration: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], resolution: ["720p"] }],
    },
    {
      name: "kling-v3 专家",
      modelName: "kling-v3:pro",
      type: "video",
      mode: ["text", "singleImage", "startEndRequired"],
      audio: false,
      durationResolutionMap: [{ duration: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], resolution: ["720p"] }],
    },
    // kling-v2-6
    {
      name: "kling-v2-6 标准",
      modelName: "kling-v2-6:std",
      type: "video",
      mode: ["text", "singleImage"],
      audio: false,
      durationResolutionMap: [{ duration: [5, 10], resolution: ["720p"] }],
    },
    {
      name: "kling-v2-6 专家",
      modelName: "kling-v2-6:pro",
      type: "video",
      mode: ["text", "singleImage", "startEndRequired"],
      audio: "optional",
      durationResolutionMap: [{ duration: [5, 10], resolution: ["1080p"] }],
    },
    // kling-v2-5-turbo
    {
      name: "kling-v2-5-turbo 标准",
      modelName: "kling-v2-5-turbo:std",
      type: "video",
      mode: ["text", "singleImage"],
      audio: false,
      durationResolutionMap: [{ duration: [5, 10], resolution: ["1080p"] }],
    },
    {
      name: "kling-v2-5-turbo 专家",
      modelName: "kling-v2-5-turbo:pro",
      type: "video",
      mode: ["text", "singleImage", "startEndRequired"],
      audio: false,
      durationResolutionMap: [{ duration: [5, 10], resolution: ["1080p"] }],
    },
    // kling-v2-1
    {
      name: "kling-v2-1 标准",
      modelName: "kling-v2-1:std",
      type: "video",
      mode: ["singleImage"],
      audio: false,
      durationResolutionMap: [{ duration: [5, 10], resolution: ["720p"] }],
    },
    {
      name: "kling-v2-1 专家",
      modelName: "kling-v2-1:pro",
      type: "video",
      mode: ["singleImage", "startEndRequired"],
      audio: false,
      durationResolutionMap: [{ duration: [5, 10], resolution: ["1080p"] }],
    },
    // kling-v2-1-master
    {
      name: "kling-v2-1 Master",
      modelName: "kling-v2-1-master:pro",
      type: "video",
      mode: ["text", "singleImage"],
      audio: false,
      durationResolutionMap: [{ duration: [5, 10], resolution: ["1080p"] }],
    },
    // kling-v2-master
    {
      name: "kling-v2 Master",
      modelName: "kling-v2-master:pro",
      type: "video",
      mode: ["text", "singleImage"],
      audio: false,
      durationResolutionMap: [{ duration: [5, 10], resolution: ["720p"] }],
    },
    // kling-v1-6
    {
      name: "kling-v1-6 标准",
      modelName: "kling-v1-6:std",
      type: "video",
      mode: ["text", "singleImage", ["imageReference:4"]],
      audio: false,
      durationResolutionMap: [{ duration: [5, 10], resolution: ["720p"] }],
    },
    {
      name: "kling-v1-6 专家",
      modelName: "kling-v1-6:pro",
      type: "video",
      mode: ["text", "singleImage", "endFrameOptional", ["imageReference:4"]],
      audio: false,
      durationResolutionMap: [{ duration: [5, 10], resolution: ["1080p"] }],
    },
    // kling-v1-5
    {
      name: "kling-v1-5 标准",
      modelName: "kling-v1-5:std",
      type: "video",
      mode: ["singleImage"],
      audio: false,
      durationResolutionMap: [{ duration: [5, 10], resolution: ["720p"] }],
    },
    {
      name: "kling-v1-5 专家",
      modelName: "kling-v1-5:pro",
      type: "video",
      mode: ["singleImage", "endFrameOptional"],
      audio: false,
      durationResolutionMap: [{ duration: [5, 10], resolution: ["1080p"] }],
    },
    // kling-v1
    {
      name: "kling-v1 标准",
      modelName: "kling-v1:std",
      type: "video",
      mode: ["text", "singleImage", "startEndRequired"],
      audio: false,
      durationResolutionMap: [{ duration: [5, 10], resolution: ["720p"] }],
    },
    {
      name: "kling-v1 专家",
      modelName: "kling-v1:pro",
      type: "video",
      mode: ["text", "singleImage", "startEndRequired"],
      audio: false,
      durationResolutionMap: [{ duration: [5, 10], resolution: ["720p"] }],
    },
  ],
};

// ============================================================
// 辅助工具
// ============================================================

/**
 * 生成可灵AI的JWT鉴权Token
 */
const generateAuthToken = (): string => {
  const now = Math.floor(Date.now() / 1000);
  const payload = {
    iss: vendor.inputValues.accessKey,
    exp: now + 1800,
    nbf: now - 5,
  };
  return jsonwebtoken.sign(payload, vendor.inputValues.secretKey, {
    algorithm: "HS256",
    header: { alg: "HS256", typ: "JWT" },
  });
};

/**
 * 获取基础请求地址
 */
const getBaseUrl = (): string => {
  return vendor.inputValues.baseUrl || "https://api-beijing.klingai.com";
};

/**
 * 从 ReferenceList 条目中提取可用的数据字符串
 * 对于 url 类型返回 url，对于 base64 类型返回纯 base64（去掉 data: 前缀）
 */
const extractRawBase64 = (ref: ReferenceList): string => {
  return ref.base64.replace(/^data:[^;]+;base64,/, "");
};

/**
 * 从 ReferenceList 条目中提取带头的 base64 或 url
 * 用于 omni-video 接口，该接口的 image_url 支持带前缀的 base64 和 url
 */
const extractImageUrl = (ref: ReferenceList): string => {
  return ref.base64.startsWith("data:") ? ref.base64 : `data:image/jpeg;base64,${ref.base64}`;
};

/**
 * 提交任务并轮询获取结果的通用函数
 */
const submitAndPoll = async (submitUrl: string, queryUrlBase: string, requestBody: any): Promise<string> => {
  const token = generateAuthToken();

  logger(`开始提交可灵AI视频生成任务: ${submitUrl}`);
  logger(
    `请求参数: ${JSON.stringify({
      ...requestBody,
      image: requestBody.image ? "[BASE64]" : undefined,
      image_tail: requestBody.image_tail ? "[BASE64]" : undefined,
      image_list: requestBody.image_list ? "[IMAGES]" : undefined,
    })}`,
  );

  const submitResp = await axios.post(submitUrl, requestBody, {
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${token}`,
    },
  });

  if (submitResp.data.code !== 0) {
    throw new Error(`提交任务失败: ${submitResp.data.message || JSON.stringify(submitResp.data)}`);
  }

  const taskId = submitResp.data.data.task_id;
  logger(`任务已提交，任务ID: ${taskId}`);

  const result = await pollTask(
    async () => {
      const freshToken = generateAuthToken();
      const queryResp = await axios.get(`${queryUrlBase}/${taskId}`, {
        headers: {
          Authorization: `Bearer ${freshToken}`,
        },
      });

      if (queryResp.data.code !== 0) {
        return { completed: true, error: `查询任务失败: ${queryResp.data.message}` };
      }

      const taskData = queryResp.data.data;
      const status = taskData.task_status;
      logger(`轮询中... 任务状态: ${status}`);

      if (status === "succeed") {
        const videoUrl = taskData.task_result?.videos?.[0]?.url;
        if (!videoUrl) {
          return { completed: true, error: "任务完成但未获取到视频URL" };
        }
        return { completed: true, data: videoUrl };
      }

      if (status === "failed") {
        return { completed: true, error: `视频生成失败: ${taskData.task_status_msg || "未知错误"}` };
      }

      return { completed: false };
    },
    5000,
    600000,
  );

  if (result.error) throw new Error(result.error);
  logger(`视频生成完成，正在转换为Base64...`);
  return await urlToBase64(result.data!);
};

// ============================================================
// 适配器函数
// ============================================================

const textRequest = (model: TextModel, think: boolean, thinkLevel: 0 | 1 | 2 | 3) => {
  throw new Error("可灵AI不支持文本模型");
};

const imageRequest = async (config: ImageConfig, model: ImageModel): Promise<string> => {
  throw new Error("可灵AI不支持图片模型");
};

const videoRequest = async (config: VideoConfig, model: VideoModel): Promise<string> => {
  if (!vendor.inputValues.accessKey) throw new Error("缺少Access Key");
  if (!vendor.inputValues.secretKey) throw new Error("缺少Secret Key");

  const baseUrl = getBaseUrl();

  // 解析 modelName，格式：kling-video-o1:pro => modelName=kling-video-o1, mode=pro
  const colonIdx = model.modelName.indexOf(":");
  const modelName = colonIdx > -1 ? model.modelName.substring(0, colonIdx) : model.modelName;
  const mode = colonIdx > -1 ? model.modelName.substring(colonIdx + 1) : "pro";

  // 判断是否为 Omni 模型
  const isOmniModel = modelName === "kling-video-o1" || modelName === "kling-v3-omni";

  // 判断当前选中的视频生成模式
  const currentMode = config.mode;
  const isText = currentMode.includes("text");
  const isSingleImage = currentMode.includes("singleImage");
  const isStartEndRequired = currentMode.includes("startEndRequired");
  const isEndFrameOptional = currentMode.includes("endFrameOptional");
  const isStartFrameOptional = currentMode.includes("startFrameOptional");
  const hasMultiRef = Array.isArray(currentMode) && currentMode.some((m) => Array.isArray(m));

  // 提取不同类型的引用
  const imageRefs = (config.referenceList || []).filter((r) => r.type === "image");
  const videoRefs = (config.referenceList || []).filter((r) => r.type === "video");

  // =====================================================
  // Omni 模型 —— 使用 /v1/videos/omni-video 接口
  // =====================================================
  if (isOmniModel) {
    const requestBody: any = {
      model_name: modelName,
      mode: mode,
      duration: String(config.duration),
      sound: config.audio === true ? "on" : "off",
    };

    if (config.prompt) {
      requestBody.prompt = config.prompt;
    }

    if (isSingleImage && imageRefs.length > 0) {
      const imageUrl = extractImageUrl(imageRefs[0]);
      requestBody.image_list = [{ image_url: imageUrl, type: "first_frame" }];
      if (!requestBody.prompt) requestBody.prompt = "根据图片生成视频";
    } else if (isStartEndRequired && imageRefs.length >= 2) {
      const firstUrl = extractImageUrl(imageRefs[0]);
      const endUrl = extractImageUrl(imageRefs[1]);
      requestBody.image_list = [
        { image_url: firstUrl, type: "first_frame" },
        { image_url: endUrl, type: "end_frame" },
      ];
      if (!requestBody.prompt) requestBody.prompt = "根据首尾帧图片生成过渡视频";
    } else if (isEndFrameOptional && imageRefs.length >= 1) {
      const firstUrl = extractImageUrl(imageRefs[0]);
      requestBody.image_list = [{ image_url: firstUrl, type: "first_frame" }];
      if (imageRefs.length >= 2) {
        const endUrl = extractImageUrl(imageRefs[1]);
        requestBody.image_list.push({ image_url: endUrl, type: "end_frame" });
      }
      if (!requestBody.prompt) requestBody.prompt = "根据图片生成视频";
    } else if (isStartFrameOptional && imageRefs.length >= 1) {
      if (imageRefs.length >= 2) {
        const firstUrl = extractImageUrl(imageRefs[0]);
        const endUrl = extractImageUrl(imageRefs[1]);
        requestBody.image_list = [
          { image_url: firstUrl, type: "first_frame" },
          { image_url: endUrl, type: "end_frame" },
        ];
      } else {
        const endUrl = extractImageUrl(imageRefs[0]);
        requestBody.image_list = [{ image_url: endUrl, type: "end_frame" }];
      }
      if (!requestBody.prompt) requestBody.prompt = "根据图片生成视频";
    } else if (hasMultiRef && (imageRefs.length > 0 || videoRefs.length > 0)) {
      requestBody.image_list = [];
      for (let i = 0; i < imageRefs.length; i++) {
        const imageUrl = extractImageUrl(imageRefs[i]);
        requestBody.image_list.push({ image_url: imageUrl });
      }
      if (!requestBody.prompt) {
        const refs = imageRefs.map((_, idx) => `<<<image_${idx + 1}>>>`).join("、");
        requestBody.prompt = `参考${refs}生成视频`;
      }
    }

    // 文生视频或无图片输入时需要设置宽高比
    const hasImageInput = requestBody.image_list && requestBody.image_list.length > 0;
    if (!hasImageInput) {
      requestBody.aspect_ratio = config.aspectRatio || "16:9";
      if (!requestBody.prompt) throw new Error("文生视频模式需要提供提示词");
    }

    const apiPath = "/v1/videos/omni-video";
    return await submitAndPoll(`${baseUrl}${apiPath}`, `${baseUrl}${apiPath}`, requestBody);
  }

  // =====================================================
  // 非 Omni 模型 —— 根据模式选择不同接口
  // =====================================================

  // 多图参考模式 —— 使用 /v1/videos/multi-image2video 接口（仅 kling-v1-6 支持）
  if (hasMultiRef && imageRefs.length > 0) {
    const imageList = [];
    for (let i = 0; i < imageRefs.length; i++) {
      const rawBase64 = extractRawBase64(imageRefs[i]);
      imageList.push({ image: rawBase64 });
    }

    const requestBody: any = {
      model_name: modelName,
      image_list: imageList,
      prompt: config.prompt || "根据参考图片生成视频",
      mode: mode,
      duration: String(config.duration),
      aspect_ratio: config.aspectRatio || "16:9",
    };

    const apiPath = "/v1/videos/multi-image2video";
    return await submitAndPoll(`${baseUrl}${apiPath}`, `${baseUrl}${apiPath}`, requestBody);
  }

  // 文生视频模式 —— 使用 /v1/videos/text2video 接口
  if (isText) {
    if (!config.prompt) throw new Error("文生视频模式需要提供提示词");

    const requestBody: any = {
      model_name: modelName,
      prompt: config.prompt,
      mode: mode,
      duration: String(config.duration),
      aspect_ratio: config.aspectRatio || "16:9",
      sound: config.audio === true ? "on" : "off",
    };

    const apiPath = "/v1/videos/text2video";
    return await submitAndPoll(`${baseUrl}${apiPath}`, `${baseUrl}${apiPath}`, requestBody);
  }

  // 图生视频模式（单图 / 首尾帧 / 尾帧可选等）—— 使用 /v1/videos/image2video 接口
  if ((isSingleImage || isStartEndRequired || isEndFrameOptional || isStartFrameOptional) && imageRefs.length > 0) {
    const requestBody: any = {
      model_name: modelName,
      prompt: config.prompt || "根据图片生成视频",
      mode: mode,
      duration: String(config.duration),
      sound: config.audio === true ? "on" : "off",
    };

    if (isSingleImage) {
      requestBody.image = extractRawBase64(imageRefs[0]);
    } else if (isStartEndRequired && imageRefs.length >= 2) {
      requestBody.image = extractRawBase64(imageRefs[0]);
      requestBody.image_tail = extractRawBase64(imageRefs[1]);
    } else if (isEndFrameOptional) {
      requestBody.image = extractRawBase64(imageRefs[0]);
      if (imageRefs.length >= 2) {
        requestBody.image_tail = extractRawBase64(imageRefs[1]);
      }
    } else if (isStartFrameOptional) {
      if (imageRefs.length >= 2) {
        requestBody.image = extractRawBase64(imageRefs[0]);
        requestBody.image_tail = extractRawBase64(imageRefs[1]);
      } else {
        requestBody.image = extractRawBase64(imageRefs[0]);
      }
    }

    const apiPath = "/v1/videos/image2video";
    return await submitAndPoll(`${baseUrl}${apiPath}`, `${baseUrl}${apiPath}`, requestBody);
  }

  throw new Error("不支持的视频生成模式或缺少必要的输入参数");
};

const ttsRequest = async (config: TTSConfig, model: TTSModel): Promise<string> => {
  return "";
};

// ============================================================
// 导出
// ============================================================

exports.vendor = vendor;
exports.textRequest = textRequest;
exports.imageRequest = imageRequest;
exports.videoRequest = videoRequest;
exports.ttsRequest = ttsRequest;

// 这行代码用于确保当前文件被识别为模块，避免全局变量冲突
export {};
