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.Claude;
const API_URL = "https://api.anthropic.com/v1/messages";
const TIMEOUT_MS = 25_000;

interface AnthropicContent {
  type: string;
  text?: string;
}

interface AnthropicBody {
  content?: AnthropicContent[];
}

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

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

  const t0 = Date.now();

  const systemPrompt =
    "You are a helpful search assistant. Answer the user's query with specific, factual information. " +
    "When relevant, mention specific businesses, products, or services that are commonly associated with the query. " +
    "Include URLs or domain names when you reference specific sources.";

  try {
    const res = await retryWithBackoff(
      () =>
        fetchWithTimeout(
          API_URL,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              "x-api-key": apiKey,
              "anthropic-version": "2023-06-01",
            },
            body: JSON.stringify({
              model: "claude-haiku-4-5-20251001",
              max_tokens: 1024,
              system: systemPrompt,
              messages: [{ role: "user", content: query }],
            }),
          },
          TIMEOUT_MS,
        ),
      1,
      (err) => err instanceof Error && err.message.includes("fetch"),
    );

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

    const body = parseJsonSafely<AnthropicBody>(await res.text());
    const textBlock = body?.content?.find((c) => c.type === "text");
    const responseText = textBlock?.text ?? null;

    const citations: Citation[] = extractUrlsFromText(responseText ?? "").map((url) => ({
      title: extractDomain(url),
      url,
      snippet: "",
      domain: extractDomain(url),
    }));

    return {
      engineInternalName: "Claude",
      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 extractUrlsFromText(text: string): string[] {
  const urlRegex = /https?:\/\/[^\s)>\]"']+/g;
  return [...new Set(text.match(urlRegex) ?? [])].slice(0, 10);
}

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