// ─── AI Search Verification Agent ─────────────────────────────────────────────

import type { EngineResponse } from "./engines/shared";
import { categorizeQueries, flattenCategorized } from "./query-categorizer";
import { attachScreenshots, buildTopCitations as aggregatorBuildTopCitations } from "./result-aggregator";

// ─── Input ────────────────────────────────────────────────────────────────────

export interface VerificationInput {
  brandName: string;
  brandUrl: string;
  industryVertical: string;
  trackedQueries: string[];
  brandCompetitors: Array<{ name: string; domain: string }>;
  brandLocation?: string;
}

// ─── Per-engine per-query result ──────────────────────────────────────────────

export interface EngineQueryResult {
  query: string;
  queryCategory: "branded" | "nonBrandedNational" | "nonBrandedLocal" | "longTailInformational";
  engineInternalName: EngineResponse["engineInternalName"];
  engineDisplayName: string;
  engineSubtitle: string;
  engineNumber: EngineResponse["engineNumber"];
  brandMentioned: boolean;
  brandPositionInResponse: number | null; // 1-based sentence position; null if not mentioned
  competitorsMentioned: string[];          // competitor display names found in response
  citationsCount: number;
  brandCited: boolean;                     // brand domain appears in citations
  citations: EngineResponse["citations"];
  responseText: string | null;
  screenshotUrl: string | null;            // Vercel Blob URL; null if unavailable
  durationMs: number;
  success: boolean;
  errorMessage: string | null;
}

// ─── Per-engine summary ───────────────────────────────────────────────────────

export interface EngineSummary {
  engineInternalName: EngineResponse["engineInternalName"];
  engineDisplayName: string;
  engineSubtitle: string;
  engineNumber: EngineResponse["engineNumber"];
  queriesRun: number;
  brandMentionRate: number;    // 0–1
  brandCitationRate: number;   // 0–1
  avgPositionWhenMentioned: number | null;
  topCompetitorsMentioned: Array<{ name: string; mentionCount: number }>;
  successRate: number;         // 0–1 (engines can fail)
}

// ─── Brand visibility summary ─────────────────────────────────────────────────

export interface BrandVisibilitySummary {
  overallMentionRate: number;       // brand mentioned / total successful queries across all engines
  overallCitationRate: number;      // brand cited / total successful queries
  brandedQueryMentionRate: number;
  nonBrandedMentionRate: number;
  localQueryMentionRate: number;
  informationalMentionRate: number;
  engineWithBestMentionRate: string;   // engineDisplayName
  engineWithWorstMentionRate: string;  // engineDisplayName
  queriesRun: number;
  queriesSuccessful: number;
}

// ─── Full result ──────────────────────────────────────────────────────────────

export interface VerificationResult {
  completedAt: string;                     // ISO timestamp
  durationMs: number;                      // total wall-clock ms
  brandName: string;
  brandUrl: string;
  queriesChecked: number;
  engineResults: EngineQueryResult[];
  engineSummaries: EngineSummary[];
  brandVisibility: BrandVisibilitySummary;
  topCitations: Array<{                    // top 10 domains cited across all engines
    domain: string;
    citationCount: number;
    isBrandDomain: boolean;
    isCompetitorDomain: boolean;
  }>;
  insights: string[];                      // 3–5 synthesized narrative insights
  degraded: boolean;                       // true if ≥1 engine returned no data
  failedEngines: EngineResponse["engineInternalName"][];
}

// ─── Orchestrator ─────────────────────────────────────────────────────────────

export async function verifyAiSearchVisibility(
  input: VerificationInput,
): Promise<VerificationResult> {
  const startMs = Date.now();

  const categorized = categorizeQueries(
    input.brandName,
    input.trackedQueries,
    input.brandLocation,
  );
  const queries = flattenCategorized(categorized);

  // Engine modules are loaded lazily to avoid import-time side-effects
  const [
    { queryChatGpt },
    { queryPerplexity },
    { queryClaude },
    { queryGemini },
    { queryBrave },
  ] = await Promise.all([
    import("./engines/chatgpt"),
    import("./engines/perplexity"),
    import("./engines/claude"),
    import("./engines/gemini"),
    import("./engines/brave"),
  ]);

  const engineFns = [queryChatGpt, queryPerplexity, queryClaude, queryGemini, queryBrave];

  // Run all engine × query combinations concurrently (engines are independent)
  const rawResults = await Promise.all(
    engineFns.flatMap((fn) =>
      queries.map(async ({ query, category }): Promise<EngineQueryResult> => {
        const res = await fn(query).catch(
          (err: unknown): EngineResponse => ({
            engineInternalName: "ChatGPT", // placeholder — overridden below
            engineNumber: 1,
            engineDisplayName: "",
            engineSubtitle: "",
            success: false,
            responseText: null,
            citations: [],
            errorMessage: String(err),
            durationMs: 0,
          }),
        );

        const brandLower = input.brandName.toLowerCase();
        const brandDomain = extractApexDomain(input.brandUrl);
        const responseText = res.responseText ?? "";
        const brandMentioned = responseText.toLowerCase().includes(brandLower);
        const brandCited = res.citations.some((c: { url: string }) =>
          extractApexDomain(c.url) === brandDomain,
        );

        const competitorsMentioned = input.brandCompetitors
          .filter((c) => responseText.toLowerCase().includes(c.name.toLowerCase()))
          .map((c) => c.name);

        let brandPosition: number | null = null;
        if (brandMentioned) {
          const sentences = responseText.split(/[.!?]+/).map((s: string) => s.trim()).filter(Boolean);
          const idx = sentences.findIndex((s) => s.toLowerCase().includes(brandLower));
          brandPosition = idx >= 0 ? idx + 1 : null;
        }

        return {
          query,
          queryCategory: category,
          engineInternalName: res.engineInternalName,
          engineDisplayName: res.engineDisplayName,
          engineSubtitle: res.engineSubtitle,
          engineNumber: res.engineNumber,
          brandMentioned,
          brandPositionInResponse: brandPosition,
          competitorsMentioned,
          citationsCount: res.citations.length,
          brandCited,
          citations: res.citations,
          responseText: res.responseText,
          screenshotUrl: null, // attached after all queries complete (see attachScreenshots)
          durationMs: res.durationMs,
          success: res.success,
          errorMessage: res.errorMessage,
        };
      }),
    ),
  );

  const enrichedResults = await attachScreenshots(rawResults, input.brandName);

  const engineSummaries = buildEngineSummaries(enrichedResults, input.brandCompetitors);
  const brandVisibility = buildBrandVisibility(enrichedResults);
  const topCitations = aggregatorBuildTopCitations(enrichedResults, input.brandUrl, input.brandCompetitors);
  const failedEngines = [
    ...new Set(
      enrichedResults.filter((r) => !r.success).map((r) => r.engineInternalName),
    ),
  ] as EngineResponse["engineInternalName"][];

  return {
    completedAt: new Date().toISOString(),
    durationMs: Date.now() - startMs,
    brandName: input.brandName,
    brandUrl: input.brandUrl,
    queriesChecked: queries.length,
    engineResults: enrichedResults,
    engineSummaries,
    brandVisibility,
    topCitations,
    insights: buildInsights(brandVisibility, engineSummaries, input.brandName),
    degraded: failedEngines.length > 0,
    failedEngines,
  };
}

// ─── Helpers ──────────────────────────────────────────────────────────────────

function extractApexDomain(url: string): string {
  try {
    const host = new URL(url.startsWith("http") ? url : `https://${url}`).hostname.replace(/^www\./, "");
    const parts = host.split(".");
    return parts.length > 2 ? parts.slice(-2).join(".") : host;
  } catch {
    return url;
  }
}

function buildEngineSummaries(
  results: EngineQueryResult[],
  competitors: VerificationInput["brandCompetitors"],
): EngineSummary[] {
  const byEngine = new Map<string, EngineQueryResult[]>();
  for (const r of results) {
    const list = byEngine.get(r.engineInternalName) ?? [];
    list.push(r);
    byEngine.set(r.engineInternalName, list);
  }

  return Array.from(byEngine.values()).map((rows) => {
    const successful = rows.filter((r) => r.success);
    const mentioned = successful.filter((r) => r.brandMentioned);
    const cited = successful.filter((r) => r.brandCited);
    const positions = mentioned
      .map((r) => r.brandPositionInResponse)
      .filter((p): p is number => p !== null);

    const competitorCounts = new Map<string, number>();
    for (const r of successful) {
      for (const c of r.competitorsMentioned) {
        competitorCounts.set(c, (competitorCounts.get(c) ?? 0) + 1);
      }
    }

    return {
      engineInternalName: rows[0].engineInternalName,
      engineDisplayName: rows[0].engineDisplayName,
      engineSubtitle: rows[0].engineSubtitle,
      engineNumber: rows[0].engineNumber,
      queriesRun: rows.length,
      brandMentionRate: successful.length ? mentioned.length / successful.length : 0,
      brandCitationRate: successful.length ? cited.length / successful.length : 0,
      avgPositionWhenMentioned:
        positions.length ? positions.reduce((a, b) => a + b, 0) / positions.length : null,
      topCompetitorsMentioned: [...competitorCounts.entries()]
        .sort((a, b) => b[1] - a[1])
        .slice(0, 5)
        .map(([name, mentionCount]) => ({ name, mentionCount })),
      successRate: rows.length ? successful.length / rows.length : 0,
    };
  });
}

function buildBrandVisibility(results: EngineQueryResult[]): BrandVisibilitySummary {
  const successful = results.filter((r) => r.success);
  const mentioned = successful.filter((r) => r.brandMentioned);
  const cited = successful.filter((r) => r.brandCited);

  const byCategory = (cat: EngineQueryResult["queryCategory"]) =>
    successful.filter((r) => r.queryCategory === cat);
  const mentionRate = (rows: EngineQueryResult[]) =>
    rows.length ? rows.filter((r) => r.brandMentioned).length / rows.length : 0;

  const engineRates = new Map<string, number>();
  const allEngineNames = [...new Set(results.map((r) => r.engineDisplayName))];
  for (const name of allEngineNames) {
    const rows = successful.filter((r) => r.engineDisplayName === name);
    engineRates.set(name, rows.length ? rows.filter((r) => r.brandMentioned).length / rows.length : 0);
  }
  const sorted = [...engineRates.entries()].sort((a, b) => b[1] - a[1]);

  return {
    overallMentionRate: successful.length ? mentioned.length / successful.length : 0,
    overallCitationRate: successful.length ? cited.length / successful.length : 0,
    brandedQueryMentionRate: mentionRate(byCategory("branded")),
    nonBrandedMentionRate: mentionRate([
      ...byCategory("nonBrandedNational"),
      ...byCategory("nonBrandedLocal"),
    ]),
    localQueryMentionRate: mentionRate(byCategory("nonBrandedLocal")),
    informationalMentionRate: mentionRate(byCategory("longTailInformational")),
    engineWithBestMentionRate: sorted[0]?.[0] ?? "",
    engineWithWorstMentionRate: sorted[sorted.length - 1]?.[0] ?? "",
    queriesRun: results.length,
    queriesSuccessful: successful.length,
  };
}

function buildInsights(
  visibility: BrandVisibilitySummary,
  summaries: EngineSummary[],
  brandName: string,
): string[] {
  const insights: string[] = [];
  const pct = (r: number) => `${Math.round(r * 100)}%`;

  insights.push(
    `${brandName} is mentioned in ${pct(visibility.overallMentionRate)} of AI engine responses across all query types.`,
  );

  if (visibility.brandedQueryMentionRate < 0.5) {
    insights.push(
      `Even on branded queries, ${brandName} is cited only ${pct(visibility.brandedQueryMentionRate)} of the time — a strong signal to improve entity presence in AI training data.`,
    );
  }

  if (visibility.nonBrandedMentionRate < 0.25) {
    insights.push(
      `Non-branded query visibility is low at ${pct(visibility.nonBrandedMentionRate)}, suggesting competitors dominate category-level AI recommendations.`,
    );
  }

  const gapEngines = summaries.filter((s) => s.brandMentionRate < 0.2 && s.successRate > 0.5);
  if (gapEngines.length) {
    insights.push(
      `${brandName} has low visibility on ${gapEngines.map((e) => e.engineDisplayName).join(", ")} — these engines warrant targeted content authority building.`,
    );
  }

  if (visibility.overallCitationRate > 0.3) {
    insights.push(
      `Citation rate of ${pct(visibility.overallCitationRate)} is above average, indicating AI engines trust and link to brand content when it appears.`,
    );
  }

  return insights.slice(0, 5);
}
