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.Perplexity;
const API_URL = "https://api.perplexity.ai/chat/completions";
const TIMEOUT_MS = 25_000;

interface PerplexityMessage {
  role: string;
  content: string;
}

interface PerplexityChoice {
  message?: PerplexityMessage;
}

interface PerplexityBody {
  choices?: PerplexityChoice[];
  citations?: string[];
}

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

async function _query(query: string): Promise<EngineResponse> {
  const apiKey = process.env.PERPLEXITY_API_KEY?.trim();
  if (!apiKey) {
    return errorResponse("PERPLEXITY_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: "sonar",
              messages: [{ role: "user", content: query }],
              return_citations: true,
            }),
          },
          TIMEOUT_MS,
        ),
      1,
      (err) => err instanceof Error && err.message.includes("fetch"),
    );

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

    const body = parseJsonSafely<PerplexityBody>(await res.text());
    const responseText = body?.choices?.[0]?.message?.content ?? null;

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

    return {
      engineInternalName: "Perplexity",
      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: "Perplexity",
    engineNumber: META.number,
    engineDisplayName: META.displayName,
    engineSubtitle: META.subtitle,
    success: false,
    responseText: null,
    citations: [],
    errorMessage: message,
    durationMs,
  };
}
