import { ENGINE_DISPLAY_META, fetchWithTimeout, retryWithBackoff, classifyError, extractDomain, parseJsonSafely } from "./shared";
import type { EngineResponse, Citation } from "./shared";
import { getCachedOrQuery } from "../cache";

const META = ENGINE_DISPLAY_META.ChatGPT;
const API_URL = "https://api.openai.com/v1/responses";
const TIMEOUT_MS = 25_000;

interface OpenAiAnnotation {
  type: string;
  url?: string;
  title?: string;
}

interface OpenAiContent {
  type: string;
  text?: string;
  annotations?: OpenAiAnnotation[];
}

interface OpenAiOutput {
  type: string;
  content?: OpenAiContent[];
}

interface OpenAiResponseBody {
  output?: OpenAiOutput[];
}

export async function queryChatGpt(query: string): Promise<EngineResponse> {
  return getCachedOrQuery("ChatGPT", query, () => _query(query));
}

async function _query(query: string): Promise<EngineResponse> {
  const apiKey = process.env.OPENAI_API_KEY?.trim();
  if (!apiKey) {
    return errorResponse("OPENAI_API_KEY not configured");
  }

  const t0 = Date.now();

  try {
    const res = await retryWithBackoff(
      () =>
        fetchWithTimeout(
          API_URL,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${apiKey}`,
            },
            body: JSON.stringify({
              model: "gpt-4o",
              tools: [{ type: "web_search_preview" }],
              input: query,
            }),
          },
          TIMEOUT_MS,
        ),
      1,
      (err) => err instanceof Error && err.message.includes("fetch"),
    );

    if (!res.ok) {
      const engineError = classifyError(res.status, `ChatGPT HTTP ${res.status}`);
      return errorResponse(engineError.message, Date.now() - t0);
    }

    const body = parseJsonSafely<OpenAiResponseBody>(await res.text());
    const messageOutput = body?.output?.find((o) => o.type === "message");
    const textContent = messageOutput?.content?.find((c) => c.type === "output_text");
    const responseText = textContent?.text ?? null;

    const citations: Citation[] = (textContent?.annotations ?? [])
      .filter((a) => a.type === "url_citation" && a.url)
      .map((a) => ({
        title: a.title ?? a.url ?? "",
        url: a.url ?? "",
        snippet: "",
        domain: extractDomain(a.url ?? ""),
      }));

    return {
      engineInternalName: "ChatGPT",
      engineNumber: META.number,
      engineDisplayName: META.displayName,
      engineSubtitle: META.subtitle,
      success: true,
      responseText,
      citations,
      errorMessage: null,
      durationMs: Date.now() - t0,
    };
  } catch (err) {
    return errorResponse(err instanceof Error ? err.message : "Unknown error", Date.now() - t0);
  }
}

function errorResponse(message: string, durationMs = 0): EngineResponse {
  return {
    engineInternalName: "ChatGPT",
    engineNumber: META.number,
    engineDisplayName: META.displayName,
    engineSubtitle: META.subtitle,
    success: false,
    responseText: null,
    citations: [],
    errorMessage: message,
    durationMs,
  };
}
