/**
 * Competitor Visual Comparison — Audit Data Source
 * ──────────────────────────────────────────────────
 * Captures brand and top-2 competitor homepages (desktop only), detects
 * visible elements, derives structural differences, and builds side-by-side
 * composite images.
 *
 * Internal module — vendor names permitted in code; forbidden in user-facing output.
 */

import { captureUrl } from "../../visual-annotation/screenshot-capture";
import { detectVisibleElements, type DetectedElements } from "../../visual-annotation/element-detector";
import { buildSideBySideComparison } from "../../visual-annotation/comparison-builder";
import { uploadScreenshot } from "../../visual-annotation/storage";
import type { CompetitorVisualComparison, VisualComparisonDifference } from "../types";

// ─── Difference detection ─────────────────────────────────────────────────────

function deriveDifferences(
  brand: DetectedElements,
  competitor: DetectedElements,
  brandName: string,
  competitorName: string,
): VisualComparisonDifference[] {
  const diffs: VisualComparisonDifference[] = [];
  let n = 1;

  function add(
    category: VisualComparisonDifference["category"],
    brandObs: string,
    compObs: string,
    impact: VisualComparisonDifference["impact"],
  ) {
    if (diffs.length >= 6) return;
    diffs.push({ number: n++, category, brandObservation: brandObs, competitorObservation: compObs, impact });
  }

  // FAQ
  if (!brand.hasFAQAccordion && competitor.hasFAQAccordion) {
    add("content_depth",
      `${brandName}: no FAQ section detected`,
      `${competitorName}: FAQ section present`,
      "high",
    );
  }

  // Review widgets
  if (!brand.hasReviewWidget && competitor.hasReviewWidget) {
    add("social_proof",
      `${brandName}: no review widget detected`,
      `${competitorName}: ${competitor.reviewWidgetType ?? "review"} widget visible`,
      "high",
    );
  }

  // Trust badges
  if (!brand.hasTrustBadges && competitor.hasTrustBadges) {
    add("trust_signals",
      `${brandName}: no certification or trust badges visible`,
      `${competitorName}: ${competitor.trustBadges.map((b) => b.type).join(", ")} badges present`,
      "moderate",
    );
  }

  // CTA quality
  const brandGeneric = brand.primaryCTAs.every((c) => /learn more|click here|read more/i.test(c.text));
  const compActionable = competitor.primaryCTAs.some((c) => !/learn more|click here|read more/i.test(c.text));
  if (brand.ctaCount > 0 && competitor.ctaCount > 0 && brandGeneric && compActionable) {
    add("cta",
      `${brandName}: generic CTA text ("${brand.primaryCTAs[0]?.text ?? "Learn More"}")`,
      `${competitorName}: action-specific CTA ("${competitor.primaryCTAs.find((c) => !/learn more/i.test(c.text))?.text ?? "Get Quote"}")`,
      "high",
    );
  } else if (brand.ctaCountInViewport === 0 && competitor.ctaCountInViewport > 0) {
    add("cta",
      `${brandName}: no CTA visible above the fold`,
      `${competitorName}: ${competitor.ctaCountInViewport} CTA(s) visible above the fold`,
      "critical",
    );
  }

  // Contact form
  if (!brand.hasContactForm && competitor.hasContactForm) {
    add("content_depth",
      `${brandName}: no contact form detected`,
      `${competitorName}: contact or inquiry form present`,
      "moderate",
    );
  }

  // Heading structure
  if (!brand.hasH1 && competitor.hasH1) {
    add("navigation",
      `${brandName}: no H1 heading detected`,
      `${competitorName}: H1 present ("${competitor.headingHierarchy.find((h) => h.level === 1)?.text?.slice(0, 40) ?? "…"}")`,
      "high",
    );
  }

  // Images without alt
  if (brand.imagesWithoutAlt > competitor.imagesWithoutAlt + 3) {
    add("content_depth",
      `${brandName}: ${brand.imagesWithoutAlt} images missing alt text`,
      `${competitorName}: ${competitor.imagesWithoutAlt} images missing alt text`,
      "low",
    );
  }

  return diffs;
}

// ─── Summary narrative ────────────────────────────────────────────────────────

function buildNarrative(
  competitorName: string,
  differences: VisualComparisonDifference[],
): string {
  if (differences.length === 0) {
    return `Structural comparison with ${competitorName} shows broadly similar page composition. No significant visible-element gaps detected.`;
  }
  const critical = differences.filter((d) => d.impact === "critical");
  const high = differences.filter((d) => d.impact === "high");
  const top = [...critical, ...high].slice(0, 2);
  const parts = top.map((d) => d.competitorObservation);
  return `${competitorName} has a structural advantage in ${top.length} area(s): ${parts.join("; ")}. Addressing these gaps would directly align the brand's above-fold composition with best-in-class competitors.`;
}

// ─── Top difference categories ────────────────────────────────────────────────

const CATEGORY_DESCRIPTIONS: Record<VisualComparisonDifference["category"], string> = {
  cta: "Call-to-action prominence and specificity",
  social_proof: "Review widgets, testimonials, and star ratings",
  trust_signals: "Certifications, badges, and guarantees",
  content_depth: "FAQ sections, forms, and informational depth",
  navigation: "Heading structure and page hierarchy",
  visual_design: "Visual hierarchy and layout composition",
};

function buildTopCategories(
  allDiffs: VisualComparisonDifference[],
): CompetitorVisualComparison["topDifferenceCategories"] {
  const counts = new Map<string, number>();
  for (const d of allDiffs) {
    counts.set(d.category, (counts.get(d.category) ?? 0) + 1);
  }
  return [...counts.entries()]
    .sort((a, b) => b[1] - a[1])
    .slice(0, 4)
    .map(([cat, count]) => ({
      category: CATEGORY_DESCRIPTIONS[cat as VisualComparisonDifference["category"]] ?? cat,
      occurrenceCount: count,
      summary: `This gap appears across ${count} competitor comparison(s), indicating a consistent structural opportunity.`,
    }));
}

// ─── Main aggregator ──────────────────────────────────────────────────────────

export async function aggregateCompetitorVisualComparison(
  brandUrl: string,
  brandName: string,
  competitors: Array<{ domain: string; avgRankPosition?: number }>,
): Promise<CompetitorVisualComparison | null> {
  if (!process.env.BLOB_READ_WRITE_TOKEN) return null;
  if (competitors.length === 0) return null;

  const start = Date.now();
  const topCompetitors = competitors.slice(0, 2);
  const allDiffs: VisualComparisonDifference[] = [];
  const comparisons: CompetitorVisualComparison["comparisons"] = [];
  let totalScreenshots = 0;

  // Capture brand homepage once
  const brandCapture = await captureUrl(brandUrl, { viewport: "desktop", fullPage: false });
  if (brandCapture) totalScreenshots++;
  const brandElements = brandCapture ? detectVisibleElements(brandCapture.dom) : null;
  const brandScreenshotUrl = brandCapture
    ? await uploadScreenshot(brandCapture.buffer, "brand-homepage", "desktop")
    : null;

  for (const comp of topCompetitors) {
    const competitorUrl = `https://${comp.domain}`;
    const competitorName = comp.domain.replace(/^www\./, "").split(".")[0] ?? comp.domain;

    try {
      const compCapture = await captureUrl(competitorUrl, { viewport: "desktop", fullPage: false });
      if (!compCapture) continue;
      totalScreenshots++;

      const compElements = detectVisibleElements(compCapture.dom);
      const compScreenshotUrl = await uploadScreenshot(compCapture.buffer, `competitor-${comp.domain}`, "desktop");
      if (!compScreenshotUrl) continue;

      const differences = brandElements
        ? deriveDifferences(brandElements, compElements, brandName, competitorName)
        : [];
      allDiffs.push(...differences);

      // Build side-by-side composite
      let sideBySideUrl: string | null = null;
      if (brandCapture && compCapture) {
        try {
          const sideBySideBuffer = await buildSideBySideComparison(
            brandCapture.buffer,
            compCapture.buffer,
            brandName,
            competitorName,
            differences,
          );
          sideBySideUrl = await uploadScreenshot(sideBySideBuffer, `comparison-${comp.domain}`, "side-by-side");
          if (sideBySideUrl) totalScreenshots++;
        } catch (err) {
          console.warn(`[competitor-visual-comparison] side-by-side build failed for ${comp.domain}:`, err instanceof Error ? err.message : err);
        }
      }

      const relevanceScore = comp.avgRankPosition
        ? Math.max(0, Math.round(100 - comp.avgRankPosition * 2))
        : 50;

      comparisons.push({
        competitorName,
        competitorUrl,
        competitorRelevanceScore: relevanceScore,
        homepageComparison: {
          brandScreenshotUrl,
          competitorScreenshotUrl: compScreenshotUrl,
          sideBySideUrl,
          differences,
        },
        servicePageComparison: null, // Desktop homepage comparison only per spec
        summaryNarrative: buildNarrative(competitorName, differences),
      });
    } catch (err) {
      console.warn(`[competitor-visual-comparison] capture failed for ${comp.domain}:`, err instanceof Error ? err.message : err);
    }
  }

  if (comparisons.length === 0) return null;

  return {
    hasComparison: true,
    windowDate: new Date().toISOString(),
    comparisons,
    topDifferenceCategories: buildTopCategories(allDiffs),
    patentRelevance:
      "Side-by-side competitor visual analysis provides multi-layer structural gap evidence beyond text analysis alone; composite overlay with numbered callouts creates actionable competitive intelligence.",
    costMetrics: {
      totalScreenshotsCaptured: totalScreenshots,
      runtimeSeconds: (Date.now() - start) / 1000,
    },
  };
}
