import {
  MIN_API_TIMEOUT_MS,
  MAX_API_TIMEOUT_MS,
  DEFAULT_API_TIMEOUT_MS,
  MIN_COMPLETION_TOKENS,
  MAX_COMPLETION_TOKENS,
} from "@/lib/constants";

export type OpenAiCompatibleChatMessage = {
  role: "system" | "user" | "assistant";
  content: string;
};

export type OpenAiCompatibleChatOptions = {
  baseUrl: string; // 形如 https://host/v1
  apiKey: string;
  model: string;
  timeoutMs?: number;
  maxTokens?: number;
  // 某些 OpenAI 兼容网关使用 max_completion_tokens 字段；如需可传入该值
  maxCompletionTokens?: number;
  responseFormat?: "json_object";
};

export const tryExtractJsonObject = (value: string): Record<string, unknown> | null => {
  const s = value ?? "";
  const start = s.indexOf("{");
  const end = s.lastIndexOf("}");
  if (start === -1 || end === -1 || end <= start) return null;
  try {
    const parsed = JSON.parse(s.slice(start, end + 1));
    if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
      return parsed as Record<string, unknown>;
    }
    return null;
  } catch {
    return null;
  }
};

export const openAiCompatibleChat = async (
  messages: OpenAiCompatibleChatMessage[],
  opts: OpenAiCompatibleChatOptions,
): Promise<{ text: string; raw: unknown }> => {
  const timeoutMs = Math.max(MIN_API_TIMEOUT_MS, Math.min(MAX_API_TIMEOUT_MS, opts.timeoutMs ?? DEFAULT_API_TIMEOUT_MS));
  const controller = new AbortController();
  const t = setTimeout(() => controller.abort(), timeoutMs);
  try {
    const url = `${opts.baseUrl.replace(/\/+$/, "")}/chat/completions`;
    const maxCompletionTokens =
      typeof opts.maxCompletionTokens === "number" && Number.isFinite(opts.maxCompletionTokens)
        ? Math.max(MIN_COMPLETION_TOKENS, Math.min(MAX_COMPLETION_TOKENS, Math.floor(opts.maxCompletionTokens)))
        : undefined;
    const maxTokens =
      typeof opts.maxTokens === "number" && Number.isFinite(opts.maxTokens)
        ? Math.max(MIN_COMPLETION_TOKENS, Math.min(MAX_COMPLETION_TOKENS, Math.floor(opts.maxTokens)))
        : undefined;
    const res = await fetch(url, {
      method: "POST",
      signal: controller.signal,
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${opts.apiKey}`,
      },
      body: JSON.stringify({
        model: opts.model,
        stream: false,
        temperature: 0.2,
        ...(maxTokens ? { max_tokens: maxTokens } : {}),
        ...(maxCompletionTokens ? { max_completion_tokens: maxCompletionTokens } : {}),
        ...(opts.responseFormat === "json_object" ? { response_format: { type: "json_object" } } : {}),
        messages,
      }),
    });

    const raw = (await res.json().catch(() => null)) as unknown;
    if (!res.ok) {
      const errText =
        typeof raw === "object" && raw && "error" in (raw as any)
          ? String((raw as any).error?.message ?? (raw as any).error)
          : `HTTP ${res.status}`;
      throw new Error(`在线 AI 调用失败：${errText}`);
    }

    const choiceText =
      (raw as any)?.choices?.[0]?.message?.content ??
      (raw as any)?.choices?.[0]?.text ??
      "";
    const text = String(choiceText ?? "");
    return { text, raw };
  } finally {
    clearTimeout(t);
  }
};

export const openAiCompatibleChatJson = async (
  messages: OpenAiCompatibleChatMessage[],
  opts: OpenAiCompatibleChatOptions,
): Promise<{ json: Record<string, unknown>; text: string; raw: unknown }> => {
  const { text, raw } = await openAiCompatibleChat(messages, opts);
  const json = tryExtractJsonObject(text);
  if (!json) {
    const preview = String(text || "").slice(0, 220).replace(/\s+/g, " ").trim();
    throw new Error(`在线 AI 未返回可解析的 JSON 对象：${preview || "(empty)"}`);
  }
  return { json, text, raw };
};
