import axios from "axios";
import u from "@/utils";
import FormData from "form-data";
import sharp from "sharp";

type VideoAspectRatio = "16:9" | "9:16" | "1:1" | "4:3" | "3:4" | "21:9" | "adaptive";
interface BaseVideoConfig {
  prompt: string;
  savePath: string;
  imageBase64?: string[]; // 单张参考图片 base64
}
interface DoubaoVideoConfig extends BaseVideoConfig {
  duration: 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; // 支持 2~12 秒
  aspectRatio: VideoAspectRatio;
  audio?: boolean;
}
interface RunninghubVideoConfig extends BaseVideoConfig {
  duration: 10 | 15; // 仅支持 10 或 15 秒
  aspectRatio: "16:9" | "9:16" | "1:1"; // 仅支持这三种比例
}
interface OpenAIVideoConfig extends BaseVideoConfig {
  duration: 10 | 15; // 仅支持 10 或 15 秒
  aspectRatio: Exclude<VideoAspectRatio, "adaptive">; // 不支持 adaptive
}
type VideoConfig = DoubaoVideoConfig | RunninghubVideoConfig | OpenAIVideoConfig;

const urlToBase64 = async (url: string): Promise<string> => {
  const res = await axios.get(url, { responseType: "arraybuffer" });
  const base64 = Buffer.from(res.data).toString("base64");
  const mimeType = res.headers["content-type"] || "image/png";
  return `data:${mimeType};base64,${base64}`;
};

const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

const pollTask = async (
  queryFn: () => Promise<{ completed: boolean; imageUrl?: string; error?: string }>,
  maxAttempts = 500,
  interval = 2000,
): Promise<string> => {
  for (let i = 0; i < maxAttempts; i++) {
    await sleep(interval);
    const { completed, imageUrl, error } = await queryFn();
    if (error) throw new Error(error);
    if (completed && imageUrl) return imageUrl;
  }
  throw new Error(`任务轮询超时，已尝试 ${maxAttempts} 次`);
};

// 上传 base64 图片到 runninghub
const uploadBase64ToRunninghub = async (base64Image: string, apiKey: string, baseURL: string): Promise<string> => {
  try {
    apiKey = apiKey.replace("Bearer ", "");
    // 移除 base64 前缀
    const base64Data = base64Image.replace(/^data:image\/\w+;base64,/, "");
    let buffer = Buffer.from(base64Data, "base64");

    // 压缩图片到 5MB 以下
    const MAX_SIZE = 5 * 1024 * 1024; // 5MB
    if (buffer.length > MAX_SIZE) {
      let quality = 90;

      while (buffer.length > MAX_SIZE && quality > 10) {
        const compressed = await sharp(buffer).jpeg({ quality, mozjpeg: true }).toBuffer();
        buffer = Buffer.from(compressed);
        quality -= 10;
      }

      // 如果仍然超过限制，进一步调整尺寸
      if (buffer.length > MAX_SIZE) {
        const metadata = await sharp(buffer).metadata();
        const scale = Math.sqrt(MAX_SIZE / buffer.length);

        const resized = await sharp(buffer)
          .resize({
            width: Math.floor((metadata.width || 1920) * scale),
            height: Math.floor((metadata.height || 1080) * scale),
            fit: "inside",
          })
          .jpeg({ quality: 80, mozjpeg: true })
          .toBuffer();

        buffer = Buffer.from(resized);
      }
    }

    // 创建 FormData
    const formData = new FormData();
    formData.append("file", buffer, {
      filename: "image.jpg",
      contentType: "image/jpeg",
    });

    // 上传图片
    const uploadRes = await axios.post(`https://www.runninghub.cn/openapi/v2/media/upload/binary`, formData, {
      headers: { Authorization: `Bearer ${apiKey}` },
    });

    if (uploadRes.data.code !== 0 || !uploadRes.data.data?.download_url) {
      throw new Error(`图片上传失败: ${JSON.stringify(uploadRes.data)}`);
    }

    return uploadRes.data.data.download_url;
  } catch (error) {
    console.error("上传图片时发生错误:", error);
    throw error;
  }
};

const generateVideoWithConfig = async (config: VideoConfig, configItem: { model: string; apiKey: string; baseURL: string; manufacturer: string }) => {
  const { apiKey, baseURL, manufacturer, model } = configItem;
  const imageArrPath = [];
  for (const imageVal of config?.imageBase64!) {
    // 判断是否为base64串
    const isBase64 = typeof imageVal === "string" && /^data:image\/[a-zA-Z0-9\+\-\.]+;base64,[\s\S]+$/.test(imageVal.trim());
    if (isBase64) {
      imageArrPath.push(imageVal);
    } else {
      const base64 = await urlToBase64(imageVal);
      imageArrPath.push(base64);
    }
  }
  config.imageBase64 = imageArrPath;
  let videoUrl: string | null = null;
  if (manufacturer === "volcengine") {
    const doubaoConfig = config as DoubaoVideoConfig;
    const createRes = await axios.post(
      baseURL ?? "https://ark.cn-beijing.volces.com/api/v3/contents/generations/tasks",
      {
        model: "doubao-seedance-1-5-pro-251215",
        content: [
          { type: "text", text: config.prompt },
          ...(doubaoConfig.imageBase64
            ? doubaoConfig.imageBase64.map((base64, i) => ({
                type: "image_url",
                image_url: { url: base64 },
                role: i === 0 ? "first_frame" : "last_frame",
              }))
            : []),
        ],
        generate_audio: doubaoConfig.audio ?? false,
        duration: doubaoConfig.duration,
        resolution: doubaoConfig.aspectRatio,
        watermark: false,
      },
      { headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` } },
    );
    const taskId = createRes.data.id;
    if (!taskId) throw new Error("视频任务创建失败");
    videoUrl = await pollTask(async () => {
      const res = await axios.get(`${baseURL ?? "https://ark.cn-beijing.volces.com/api/v3/contents/generations/tasks"}/${taskId}`, {
        headers: { Authorization: `Bearer ${apiKey}` },
      });
      const { status, content } = res.data;
      if (status === "succeeded") return { completed: true, imageUrl: content?.video_url };
      if (["failed", "cancelled", "expired"].includes(status)) return { completed: false, error: `任务${status}` };
      if (["queued", "running"].includes(status)) return { completed: false };
      return { completed: false, error: `未知状态: ${status}` };
    });
  } else if (manufacturer === "runninghub") {
    const runninghubConfig = config as RunninghubVideoConfig;
    // 如果有图片，先上传
    let uploadedImageUrl: string | undefined;
    if (runninghubConfig.imageBase64 && runninghubConfig.imageBase64.length > 0) {
      uploadedImageUrl = await uploadBase64ToRunninghub(runninghubConfig.imageBase64[0]!, apiKey ?? "", "https://www.runninghub.cn");
    }

    const endpoint = uploadedImageUrl ? "/openapi/v2/rhart-video-s/image-to-video" : "/openapi/v2/rhart-video-s/text-to-video";
    const requestBody = uploadedImageUrl
      ? {
          prompt: config.prompt,
          imageUrl: uploadedImageUrl,
          duration: String(runninghubConfig.duration) as "10" | "15",
          aspectRatio: runninghubConfig.aspectRatio,
        }
      : { prompt: config.prompt, model };
    const createRes = await axios.post(`https://www.runninghub.cn${endpoint}`, requestBody, {
      headers: { Authorization: "Bearer " + apiKey, "Content-Type": "application/json" },
    });

    const { taskId, status: initialStatus, errorMessage } = createRes.data;
    if (!taskId) throw new Error(`视频任务创建失败: ${errorMessage || "未知错误"}`);
    if (initialStatus === "FAILED") throw new Error(`任务创建失败: ${errorMessage}`);
    videoUrl = await pollTask(async () => {
      const res = await axios.post(
        `https://www.runninghub.cn/task/openapi/outputs`,
        { apiKey: apiKey?.replace("Bearer ", ""), taskId },
        { headers: { Authorization: "Bearer " + apiKey } },
      );
      const { code, msg, data } = res.data;

      // 成功完成
      if (code === 0 && msg === "success" && data?.[0]?.fileUrl) {
        return { completed: true, imageUrl: data[0].fileUrl };
      }

      // 进行中
      if (code === 804 || code === 813) {
        return { completed: false };
      }

      // 失败
      if (code === 805) {
        const failedReason = data?.[0]?.failedReason;
        let errorMsg = "未知原因";

        if (failedReason) {
          // 尝试多种可能的错误信息字段
          errorMsg =
            failedReason.exception_message ||
            failedReason.exceptionMessage ||
            failedReason.message ||
            failedReason.reason ||
            JSON.stringify(failedReason);
        }

        return {
          completed: false,
          error: `任务失败: ${errorMsg}`,
        };
      }

      // 其他未知状态
      return {
        completed: false,
        error: `未知状态: code=${code}, msg=${msg}, data=${JSON.stringify(data)}`,
      };
    });
  } else if (manufacturer === "openAi") {
    const openaiConfig = config as OpenAIVideoConfig;
    // 如果有图片，先上传
    let uploadedImageUrl: string | undefined;
    if (openaiConfig.imageBase64 && openaiConfig.imageBase64.length) {
      const base64Data = openaiConfig.imageBase64[0]!.replace(/^data:image\/\w+;base64,/, "");
      const buffer = Buffer.from(base64Data, "base64");
      const formData = new FormData();
      formData.append("file", buffer, { filename: "image.jpg", contentType: "image/jpeg" });
      const uploadRes = await axios.post(`${baseURL}/videos`, formData, {
        headers: {
          Authorization: `Bearer ${apiKey}`,
          ...formData.getHeaders(),
        },
      });
      uploadedImageUrl = uploadRes.data?.id || uploadRes.data?.url;
    }

    // 创建视频生成任务
    const formData = new FormData();
    formData.append("model", model);
    formData.append("prompt", config.prompt);
    formData.append("seconds", String(openaiConfig.duration));

    // 根据 aspectRatio 设置 size
    const sizeMap: Record<string, string> = {
      "16:9": "1920x1080",
      "9:16": "1080x1920",
      "1:1": "1080x1080",
      "4:3": "1440x1080",
      "3:4": "1080x1440",
      "21:9": "2560x1080",
    };
    formData.append("size", sizeMap[openaiConfig.aspectRatio] || "1920x1080");
    if (uploadedImageUrl) {
      formData.append("input_reference", uploadedImageUrl);
    }
    const createRes = await axios.post(`${baseURL}/videos`, formData, {
      headers: {
        Authorization: `Bearer ${apiKey}`,
        ...formData.getHeaders(),
      },
    });

    const taskId = createRes.data?.id;

    if (!taskId) throw new Error("视频任务创建失败");
    // 轮询任务状态
    videoUrl = await pollTask(async () => {
      const res = await axios.get(`${baseURL}/videos/${taskId}`, {
        headers: {
          Authorization: `Bearer ${apiKey}`,
          "Content-Type": "application/json",
        },
      });
      const { status, imageUrl, failReason } = res.data;
      if (status === "SUCCESS") return { completed: true, imageUrl };
      if (status === "FAILURE" || status === "CANCEL") {
        return { completed: false, error: `任务${status}: ${failReason || "未知原因"}` };
      }
      if (["NOT_START", "SUBMITTED", "IN_PROGRESS", "MODAL"].includes(status)) {
        return { completed: false };
      }
      return { completed: false, error: `未知状态: ${status}` };
    });
  } else if (manufacturer === "apimart") {
    // apimart 视频生成
    const apimartConfig = config as OpenAIVideoConfig;
    const apimartBaseURL = "https://api.apimart.ai";

    // 上传图片到 apimart 图床
    let imageUrls: string[] = [];
    if (apimartConfig.imageBase64 && apimartConfig.imageBase64.length > 0) {
      for (const base64Image of apimartConfig.imageBase64) {
        // 如果已经是 URL，直接使用
        if (base64Image.startsWith("http")) {
          imageUrls.push(base64Image);
          continue;
        }

        // 获取预签名 URL
        const presignRes = await axios.post(
          "https://apimart.ai/api/upload/presign",
          { contentType: "image/jpeg", fileExtension: "jpeg", permanent: false },
          { headers: { "Content-Type": "application/json" } },
        );

        if (!presignRes.data.success || !presignRes.data.presignedUrl || !presignRes.data.cdnUrl) {
          throw new Error(`获取预签名 URL 失败: ${JSON.stringify(presignRes.data)}`);
        }

        const { presignedUrl, cdnUrl } = presignRes.data;

        // 移除 base64 前缀并转为 buffer
        const base64Data = base64Image.replace(/^data:image\/\w+;base64,/, "");
        const buffer = Buffer.from(base64Data, "base64");

        // 上传图片到预签名 URL
        await axios.put(presignedUrl, buffer, {
          headers: { "Content-Type": "image/jpeg" },
        });

        imageUrls.push(cdnUrl);
      }
    }

    // 创建视频生成任务
    const requestBody: {
      model: string;
      prompt: string;
      duration: number;
      aspect_ratio: string;
      image_urls?: string[];
    } = {
      model: model || "sora-2",
      prompt: config.prompt,
      duration: apimartConfig.duration,
      aspect_ratio: apimartConfig.aspectRatio,
    };

    if (imageUrls.length > 0) {
      requestBody.image_urls = imageUrls;
    }

    const createRes = await axios.post(`${apimartBaseURL}/v1/videos/generations`, requestBody, {
      headers: {
        Authorization: `Bearer ${apiKey}`,
        "Content-Type": "application/json",
      },
    });

    if (createRes.data.code !== 200 || !createRes.data.data?.[0]?.task_id) {
      const errorMsg = createRes.data.error?.message || JSON.stringify(createRes.data);
      throw new Error(`视频任务创建失败: ${errorMsg}`);
    }

    const taskId = createRes.data.data[0].task_id;

    // 轮询任务状态
    videoUrl = await pollTask(async () => {
      const res = await axios.get(`${apimartBaseURL}/v1/tasks/${taskId}`, {
        headers: { Authorization: `Bearer ${apiKey}` },
        params: { language: "en" },
      });

      // 检查是否有错误
      if (res.data.error) {
        return {
          completed: false,
          error: `查询失败: ${res.data.error.message || JSON.stringify(res.data.error)}`,
        };
      }

      if (res.data.code !== 200) {
        return { completed: false, error: `查询失败: ${JSON.stringify(res.data)}` };
      }

      const { status, result } = res.data.data;

      if (status === "completed") {
        // 获取视频 URL
        const videoUrlResult = result?.videos?.[0]?.url?.[0];
        return { completed: true, imageUrl: videoUrlResult };
      }

      if (status === "failed" || status === "cancelled") {
        return { completed: false, error: `任务${status}` };
      }

      // 其他状态（submitted, processing 等）继续轮询
      return { completed: false };
    });
  } else {
    throw new Error(`不支持的厂商: ${manufacturer}`);
  }
  return videoUrl;
};

export default async (config: VideoConfig, manufacturer: string) => {
  if (!config.imageBase64 || config.imageBase64.length <= 0) throw new Error("未传图片");
  const configItem = await u.getConfig("video", manufacturer);
  if (!configItem) {
    throw new Error("未找到任何视频配置");
  }
  let lastError: Error | null = null;
  //   for (const configItem of configList) {
  // 每个配置项重试1次，共2次尝试
  for (let attempt = 0; attempt < 2; attempt++) {
    try {
      const videoUrl = await generateVideoWithConfig(config, configItem);
      if (videoUrl) {
        const response = await axios.get(videoUrl, { responseType: "stream" });
        await u.oss.writeFile(config.savePath, response.data);
        return config.savePath;
      }
      return videoUrl;
    } catch (error: any) {
      lastError = error as Error;
      console.warn(`配置 ${configItem.model} 第 ${attempt + 1} 次尝试失败:`, error?.response?.data || error.message);
      // 如果是第一次尝试失败，继续重试
      if (attempt === 0) continue;
      // 第二次也失败了,跳到下一个配置项
      break;
    }
  }
  //   }
  // 所有配置都失败了
  throw new Error(`所有视频配置都失败了。最后一次错误: ${lastError?.message || "未知错误"}`);
};
