/**
 * 统一 AI Provider 适配层
 *
 * 支持的服务商：
 *  - lovable     ：Lovable AI Gateway（默认兜底，自动注入 LOVABLE_API_KEY）
 *  - qwen        ：阿里云 DashScope（千问 / 通义万相），需要 QWEN_API_KEY
 *  - volcengine  ：火山方舟（豆包 Doubao），需要 ARK_API_KEY + ARK_ENDPOINT_TEXT/IMAGE
 *
 * 路由规则：从 ai_provider_configs 表按 purpose 读取 provider+model+extra
 *           找不到时回退到 purpose='default'，再找不到则用 lovable + gemini-2.5-flash
 *
 * 失败策略：直接抛错（用户选择不静默回退）
 */
import { createClient } from "https://esm.sh/@supabase/supabase-js@2.45.0";

const SUPABASE_URL = Deno.env.get("SUPABASE_URL")!;
const SERVICE_ROLE = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!;

export interface ProviderConfig {
  provider: "lovable" | "qwen" | "volcengine";
  model: string;
  extra: Record<string, unknown>;
}

// ============ AI Hub (OpenAI-compatible 中台) ============
// 所有 lovable 通道文本调用优先走中台，未配置时回退 Lovable Gateway
const AI_HUB_API_KEY = Deno.env.get("AI_HUB_API_KEY") || "";
const AI_HUB_BASE_URL = (Deno.env.get("AI_HUB_BASE_URL") || "").replace(/\/+$/, "");
const AI_HUB_DEFAULT_CHAT_MODEL = Deno.env.get("AI_HUB_DEFAULT_CHAT_MODEL") || "agent-default";
const AI_HUB_DEFAULT_EMBED_MODEL = Deno.env.get("AI_HUB_DEFAULT_EMBED_MODEL") || "text-embedding-3-small";

export function aiHubEnabled(): boolean {
  return !!(AI_HUB_API_KEY && AI_HUB_BASE_URL);
}

/** 把 Lovable Gateway 风格模型名映射为中台模型名 */
function mapModelToHub(model: string): string {
  if (!model) return AI_HUB_DEFAULT_CHAT_MODEL;
  // Lovable 模型字符串（google/openai 前缀）走中台默认 agent
  if (/^(google|openai|anthropic)\//i.test(model)) return AI_HUB_DEFAULT_CHAT_MODEL;
  return model;
}

export interface AIError extends Error {
  status?: number;
  code?: "rate_limit" | "quota" | "config" | "upstream";
}

function makeErr(msg: string, status?: number, code?: AIError["code"]): AIError {
  const e = new Error(msg) as AIError;
  e.status = status;
  e.code = code;
  return e;
}

/** 读取某用途的 provider 配置 */
export async function loadProviderConfig(purpose: string): Promise<ProviderConfig> {
  const admin = createClient(SUPABASE_URL, SERVICE_ROLE);
  const { data, error } = await admin
    .from("ai_provider_configs")
    .select("purpose, provider, model, extra, enabled")
    .in("purpose", [purpose, "default"])
    .order("purpose", { ascending: purpose === "default" });
  if (error) {
    throw makeErr(`[aiProvider] DB查询失败: ${error.message} (code: ${error.code})`, 500, "config");
  }
  if (!data || data.length === 0) {
    throw makeErr(`[aiProvider] 表 ai_provider_configs 无数据，请检查 purpose=${purpose}`, 500, "config");
  }
  const cfg = data?.find((r) => r.purpose === purpose && r.enabled !== false)
    || data?.find((r) => r.purpose === "default" && r.enabled !== false);
  if (!cfg) {
    throw makeErr(`[aiProvider] 未找到 purpose=${purpose} 或 default 的启用配置，当前数据: ${JSON.stringify(data)}`, 500, "config");
  }
  return {
    provider: (cfg.provider as ProviderConfig["provider"]) || "lovable",
    model: cfg.model || "google/gemini-2.5-flash",
    extra: (cfg.extra as Record<string, unknown>) || {},
  };
}

// ============ Text generation ============

export interface TextRequest {
  system?: string;
  user: string;
  temperature?: number;
}

export async function generateText(
  purpose: string,
  req: TextRequest,
): Promise<string> {
  const cfg = await loadProviderConfig(purpose);
  switch (cfg.provider) {
    case "qwen":
      return await callQwenText(cfg, req);
    case "volcengine":
      return await callArkText(cfg, req);
    case "lovable":
    default:
      return await callLovableText(cfg, req);
  }
}

async function callLovableText(cfg: ProviderConfig, req: TextRequest): Promise<string> {
  const messages: any[] = [];
  if (req.system) messages.push({ role: "system", content: req.system });
  messages.push({ role: "user", content: req.user });

  // 优先走 AI 中台
  if (aiHubEnabled()) {
    const r = await fetch(`${AI_HUB_BASE_URL}/chat/completions`, {
      method: "POST",
      headers: { Authorization: `Bearer ${AI_HUB_API_KEY}`, "Content-Type": "application/json" },
      body: JSON.stringify({ model: mapModelToHub(cfg.model), messages, stream: false }),
    });
    if (!r.ok) await throwUpstream("aihub", r);
    const j = await r.json();
    const text = j?.choices?.[0]?.message?.content?.trim() ?? "";
    if (!text) throw makeErr("AI 中台返回空内容", 500, "upstream");
    return text;
  }

  const key = Deno.env.get("LOVABLE_API_KEY");
  if (!key) throw makeErr("LOVABLE_API_KEY 未配置", 500, "config");
  const r = await fetch("https://ai.gateway.lovable.dev/v1/chat/completions", {
    method: "POST",
    headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
    body: JSON.stringify({ model: cfg.model || "google/gemini-2.5-flash", messages }),
  });
  if (!r.ok) await throwUpstream("lovable", r);
  const j = await r.json();
  const text = j?.choices?.[0]?.message?.content?.trim() ?? "";
  if (!text) throw makeErr("Lovable AI 返回空内容", 500, "upstream");
  return text;
}

// ============ Embeddings (统一走 AI 中台) ============

export async function generateEmbedding(input: string, model?: string): Promise<number[]> {
  if (!aiHubEnabled()) {
    throw makeErr("AI_HUB_API_KEY/AI_HUB_BASE_URL 未配置，无法生成向量", 500, "config");
  }
  const r = await fetch(`${AI_HUB_BASE_URL}/embeddings`, {
    method: "POST",
    headers: { Authorization: `Bearer ${AI_HUB_API_KEY}`, "Content-Type": "application/json" },
    body: JSON.stringify({ model: model || AI_HUB_DEFAULT_EMBED_MODEL, input }),
  });
  if (!r.ok) await throwUpstream("aihub-embed", r);
  const j = await r.json();
  const vec = j?.data?.[0]?.embedding;
  if (!Array.isArray(vec) || vec.length === 0) {
    throw makeErr("AI 中台未返回向量", 500, "upstream");
  }
  return vec as number[];
}

async function callQwenText(cfg: ProviderConfig, req: TextRequest): Promise<string> {
  const key = Deno.env.get("QWEN_API_KEY");
  if (!key) throw makeErr("QWEN_API_KEY 未配置（请在后台 Secrets 中添加）", 500, "config");
  // DashScope 兼容 OpenAI 风格
  const messages: any[] = [];
  if (req.system) messages.push({ role: "system", content: req.system });
  messages.push({ role: "user", content: req.user });
  const r = await fetch(
    "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions",
    {
      method: "POST",
      headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
      body: JSON.stringify({ model: cfg.model || "qwen-plus", messages }),
    },
  );
  if (!r.ok) await throwUpstream("qwen", r);
  const j = await r.json();
  const text = j?.choices?.[0]?.message?.content?.trim() ?? "";
  if (!text) throw makeErr("千问返回空内容", 500, "upstream");
  return text;
}

async function callArkText(cfg: ProviderConfig, req: TextRequest): Promise<string> {
  const key = Deno.env.get("ARK_API_KEY");
  if (!key) throw makeErr("ARK_API_KEY 未配置（请在后台 Secrets 中添加）", 500, "config");
  // 火山方舟模型字段使用 endpoint_id；优先取 cfg.model（用户填的 ep-xxx），否则取 ARK_ENDPOINT_TEXT
  const endpointId = cfg.model || Deno.env.get("ARK_ENDPOINT_TEXT") || "";
  if (!endpointId) throw makeErr("火山方舟 endpoint_id 未配置", 500, "config");
  const messages: any[] = [];
  if (req.system) messages.push({ role: "system", content: req.system });
  messages.push({ role: "user", content: req.user });
  const r = await fetch("https://ark.cn-beijing.volces.com/api/v3/chat/completions", {
    method: "POST",
    headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
    body: JSON.stringify({ model: endpointId, messages }),
  });
  if (!r.ok) await throwUpstream("volcengine", r);
  const j = await r.json();
  const text = j?.choices?.[0]?.message?.content?.trim() ?? "";
  if (!text) throw makeErr("火山方舟返回空内容", 500, "upstream");
  return text;
}

// ============ Image generation ============

export interface ImageRequest {
  prompt: string;
  size?: string; // 1024x1024 等
  /** 参考图（image-to-image 编辑），http(s) URL 或 data:image/...;base64,... */
  referenceImages?: string[];
}

export interface ImageResult {
  /** base64 编码的图片字节 */
  base64: string;
  /** image/png | image/jpeg */
  mime: string;
}

export async function generateImage(
  purpose: string,
  req: ImageRequest,
): Promise<ImageResult> {
  const cfg = await loadProviderConfig(purpose);
  switch (cfg.provider) {
    case "qwen":
      return await callQwenImage(cfg, req);
    case "volcengine":
      return await callArkImage(cfg, req);
    case "lovable":
    default:
      return await callLovableImage(cfg, req);
  }
}

/** 一次返回多张图，目前仅 lovable 通道支持 */
export async function generateImagesMulti(
  purpose: string,
  req: ImageRequest,
  count: number,
): Promise<ImageResult[]> {
  const cfg = await loadProviderConfig(purpose);
  // 当前 Gemini image 输出多图能力不稳定，统一并发 N 次单图调用
  const tasks = Array.from({ length: count }, () => generateImage(purpose, req));
  return await Promise.all(tasks);
}

async function callLovableImage(cfg: ProviderConfig, req: ImageRequest): Promise<ImageResult> {
  const key = Deno.env.get("LOVABLE_API_KEY");
  if (!key) throw makeErr("LOVABLE_API_KEY 未配置", 500, "config");

  // 构造 user content：可携带参考图（image-to-image）
  const userContent: any[] = [{ type: "text", text: req.prompt }];
  if (req.referenceImages?.length) {
    for (const url of req.referenceImages) {
      userContent.push({ type: "image_url", image_url: { url } });
    }
  }

  const r = await fetch("https://ai.gateway.lovable.dev/v1/chat/completions", {
    method: "POST",
    headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
    body: JSON.stringify({
      model: cfg.model || "google/gemini-2.5-flash-image",
      messages: [{ role: "user", content: userContent }],
      modalities: ["image", "text"],
    }),
  });
  if (!r.ok) await throwUpstream("lovable", r);
  const j = await r.json();
  const dataUrl: string | undefined = j?.choices?.[0]?.message?.images?.[0]?.image_url?.url;
  if (!dataUrl) throw makeErr("Lovable AI 未返回图片", 500, "upstream");
  const m = dataUrl.match(/^data:(image\/[a-zA-Z+]+);base64,(.+)$/);
  if (!m) throw makeErr("Lovable AI 图片格式异常", 500, "upstream");
  return { mime: m[1], base64: m[2] };
}

async function callQwenImage(cfg: ProviderConfig, req: ImageRequest): Promise<ImageResult> {
  const key = Deno.env.get("QWEN_API_KEY");
  if (!key) throw makeErr("QWEN_API_KEY 未配置（请在后台 Secrets 中添加）", 500, "config");
  // 通义万相文生图 - 异步任务模式
  const createResp = await fetch(
    "https://dashscope.aliyuncs.com/api/v1/services/aigc/text2image/image-synthesis",
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${key}`,
        "Content-Type": "application/json",
        "X-DashScope-Async": "enable",
      },
      body: JSON.stringify({
        model: cfg.model || "wanx-v1",
        input: { prompt: req.prompt },
        parameters: { size: req.size || "1024*1024", n: 1 },
      }),
    },
  );
  if (!createResp.ok) await throwUpstream("qwen", createResp);
  const createJson = await createResp.json();
  const taskId = createJson?.output?.task_id;
  if (!taskId) throw makeErr("千问文生图任务创建失败", 500, "upstream");

  // 轮询结果（最多 60s）
  let imgUrl: string | null = null;
  for (let i = 0; i < 30; i++) {
    await new Promise((res) => setTimeout(res, 2000));
    const poll = await fetch(
      `https://dashscope.aliyuncs.com/api/v1/tasks/${taskId}`,
      { headers: { Authorization: `Bearer ${key}` } },
    );
    const pollJson = await poll.json();
    const status = pollJson?.output?.task_status;
    if (status === "SUCCEEDED") {
      imgUrl = pollJson?.output?.results?.[0]?.url;
      break;
    }
    if (status === "FAILED") {
      throw makeErr(`千问文生图失败：${pollJson?.output?.message || "unknown"}`, 500, "upstream");
    }
  }
  if (!imgUrl) throw makeErr("千问文生图超时", 504, "upstream");

  const imgResp = await fetch(imgUrl);
  const buf = new Uint8Array(await imgResp.arrayBuffer());
  const mime = imgResp.headers.get("content-type") || "image/png";
  return { mime, base64: bytesToBase64(buf) };
}

async function callArkImage(cfg: ProviderConfig, req: ImageRequest): Promise<ImageResult> {
  const key = Deno.env.get("ARK_API_KEY");
  if (!key) throw makeErr("ARK_API_KEY 未配置（请在后台 Secrets 中添加）", 500, "config");
  const endpointId = cfg.model || Deno.env.get("ARK_ENDPOINT_IMAGE") || "";
  if (!endpointId) throw makeErr("火山方舟 image endpoint_id 未配置", 500, "config");
  // 火山方舟图像生成（OpenAI 兼容 images/generations）
  const r = await fetch("https://ark.cn-beijing.volces.com/api/v3/images/generations", {
    method: "POST",
    headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
    body: JSON.stringify({
      model: endpointId,
      prompt: req.prompt,
      size: req.size || "1920x1920",
      response_format: "b64_json",
    }),
  });
  if (!r.ok) await throwUpstream("volcengine", r);
  const j = await r.json();
  const b64: string | undefined = j?.data?.[0]?.b64_json;
  const url: string | undefined = j?.data?.[0]?.url;
  if (b64) return { mime: "image/png", base64: b64 };
  if (url) {
    const imgResp = await fetch(url);
    const buf = new Uint8Array(await imgResp.arrayBuffer());
    const mime = imgResp.headers.get("content-type") || "image/png";
    return { mime, base64: bytesToBase64(buf) };
  }
  throw makeErr("火山方舟未返回图片", 500, "upstream");
}

// ============ Video generation ============

export interface VideoRequest {
  prompt: string;
  /** 参考图（图生视频），http(s) URL */
  referenceImage?: string;
  /** 视频时长秒数：5 或 10 */
  duration?: 5 | 10;
  /** 宽高比尺寸 */
  size?: string; // 例如 1280*720 / 720*1280 / 960*960
}

export interface VideoResult {
  bytes: Uint8Array;
  mime: string; // video/mp4
}

export async function generateVideo(
  purpose: string,
  req: VideoRequest,
): Promise<VideoResult> {
  const cfg = await loadProviderConfig(purpose);
  // 视频生成目前仅支持通义万相，其他配置自动落到 qwen 通道
  return await callQwenVideo({ ...cfg, provider: "qwen" }, req);
}

async function callQwenVideo(cfg: ProviderConfig, req: VideoRequest): Promise<VideoResult> {
  const key = Deno.env.get("QWEN_API_KEY");
  if (!key) throw makeErr("QWEN_API_KEY 未配置（请在后台 Secrets 中添加）", 500, "config");

  const isImg2Video = !!req.referenceImage;
  const model = cfg.model || (isImg2Video ? "wanx2.1-i2v-turbo" : "wanx2.1-t2v-turbo");
  const endpoint =
    "https://dashscope.aliyuncs.com/api/v1/services/aigc/video-generation/video-synthesis";

  const input: Record<string, unknown> = { prompt: req.prompt };
  if (isImg2Video) input.img_url = req.referenceImage;

  const parameters: Record<string, unknown> = {};
  // 仅 plus 系列模型支持自定义时长（turbo 固定 5s，传入会报 "duration customization is not supported"）
  if (/plus/i.test(model) && req.duration) {
    parameters.duration = req.duration;
  }
  if (!isImg2Video) parameters.size = req.size || "1280*720";

  const createResp = await fetch(endpoint, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${key}`,
      "Content-Type": "application/json",
      "X-DashScope-Async": "enable",
    },
    body: JSON.stringify({ model, input, parameters }),
  });
  if (!createResp.ok) await throwUpstream("qwen", createResp);
  const createJson = await createResp.json();
  const taskId = createJson?.output?.task_id;
  if (!taskId) {
    throw makeErr(
      `通义万相视频任务创建失败：${JSON.stringify(createJson).slice(0, 300)}`,
      500,
      "upstream",
    );
  }

  // 轮询：视频较慢，最长 8 分钟
  let videoUrl: string | null = null;
  for (let i = 0; i < 160; i++) {
    await new Promise((res) => setTimeout(res, 3000));
    const poll = await fetch(
      `https://dashscope.aliyuncs.com/api/v1/tasks/${taskId}`,
      { headers: { Authorization: `Bearer ${key}` } },
    );
    const pollJson = await poll.json();
    const status = pollJson?.output?.task_status;
    if (status === "SUCCEEDED") {
      videoUrl = pollJson?.output?.video_url
        || pollJson?.output?.results?.video_url
        || pollJson?.output?.results?.[0]?.url;
      break;
    }
    if (status === "FAILED" || status === "UNKNOWN") {
      throw makeErr(
        `通义万相视频生成失败：${pollJson?.output?.message || JSON.stringify(pollJson?.output).slice(0, 200)}`,
        500,
        "upstream",
      );
    }
  }
  if (!videoUrl) throw makeErr("通义万相视频生成超时（>8分钟）", 504, "upstream");

  const vResp = await fetch(videoUrl);
  if (!vResp.ok) throw makeErr(`下载生成的视频失败：${vResp.status}`, 500, "upstream");
  const buf = new Uint8Array(await vResp.arrayBuffer());
  const mime = vResp.headers.get("content-type") || "video/mp4";
  return { bytes: buf, mime };
}

// ============ helpers ============

async function throwUpstream(provider: string, r: Response): Promise<never> {
  const text = await r.text().catch(() => "");
  console.error(`[aiProvider:${provider}] upstream ${r.status}`, text);
  if (r.status === 429) throw makeErr(`${provider} 调用过于频繁，请稍后再试`, 429, "rate_limit");
  if (r.status === 402) throw makeErr(`${provider} 额度不足，请充值后重试`, 402, "quota");
  if (r.status === 401 || r.status === 403) {
    throw makeErr(`${provider} 鉴权失败，请检查 API Key`, r.status, "config");
  }
  throw makeErr(`${provider} 调用失败 [${r.status}]: ${text.slice(0, 200)}`, 500, "upstream");
}

function bytesToBase64(bytes: Uint8Array): string {
  let bin = "";
  const chunk = 0x8000;
  for (let i = 0; i < bytes.length; i += chunk) {
    bin += String.fromCharCode(...bytes.subarray(i, i + chunk));
  }
  return btoa(bin);
}

export function base64ToBytes(b64: string): Uint8Array {
  const bin = atob(b64);
  const arr = new Uint8Array(bin.length);
  for (let i = 0; i < bin.length; i++) arr[i] = bin.charCodeAt(i);
  return arr;
}
