/**
 * Visual Annotation — Annotation Generator
 * ──────────────────────────────────────────
 * Produces annotation specs from detected elements + industry context.
 * Rules are industry-aware and capped at 8 per page.
 *
 * Internal module — vendor names permitted in code; forbidden in user-facing output.
 */

import type { DetectedElements, BoundingBox } from "./element-detector";

export interface AnnotationSpec {
  id: string;
  severity: "critical" | "high" | "moderate" | "low" | "positive";
  boundingBox: BoundingBox;
  shape: "box" | "arrow" | "circle";
  color: string;
  number: number;
  shortLabel: string;
  description: string;
  linkedFindingTitle: string | null;
  linkedAction: string | null;
}

const SEVERITY_COLOR: Record<AnnotationSpec["severity"], string> = {
  critical: "#DC2626",
  high: "#EA580C",
  moderate: "#D97706",
  low: "#6B7280",
  positive: "#059669",
};

const LOCAL_VERTICALS = new Set(["local-services", "healthcare-medical", "restaurant", "legal", "real-estate"]);
const ECOMMERCE_VERTICALS = new Set(["ecommerce"]);
const B2B_VERTICALS = new Set(["b2b-saas"]);

function makeBB(x: number, y: number, w: number, h: number): BoundingBox {
  return { x, y, width: w, height: h };
}

function makeSpec(
  id: string,
  number: number,
  severity: AnnotationSpec["severity"],
  boundingBox: BoundingBox,
  shortLabel: string,
  description: string,
  linkedFindingTitle: string | null = null,
  linkedAction: string | null = null,
): AnnotationSpec {
  return {
    id,
    severity,
    boundingBox,
    shape: boundingBox.width < 80 ? "arrow" : "box",
    color: SEVERITY_COLOR[severity],
    number,
    shortLabel,
    description,
    linkedFindingTitle,
    linkedAction,
  };
}

export interface BrandContext {
  brandName: string;
  hasSchemaDetected?: boolean;
  hasLocalSchema?: boolean;
  services?: string[];
}

export function generateAnnotations(
  detected: DetectedElements,
  brandContext: BrandContext,
  industryVertical: string,
): AnnotationSpec[] {
  const specs: AnnotationSpec[] = [];
  let num = 1;

  function add(s: Omit<AnnotationSpec, "number" | "color" | "shape">) {
    if (specs.length >= 8) return;
    specs.push({
      ...s,
      number: num++,
      color: SEVERITY_COLOR[s.severity],
      shape: s.boundingBox.width < 80 ? "arrow" : "box",
    });
  }

  const hero = detected.pageLoadIndicators;

  // ── Hero section ──────────────────────────────────────────────────────────
  if (hero.hasHeroSection) {
    const bb = hero.heroBoundingBox ?? makeBB(0, 0, 1280, 400);
    if (!hero.heroHasHeadline || !hero.heroHasSubheadline || !hero.heroHasCTA) {
      const missing: string[] = [];
      if (!hero.heroHasHeadline) missing.push("headline");
      if (!hero.heroHasSubheadline) missing.push("subheadline");
      if (!hero.heroHasCTA) missing.push("CTA");
      add(makeSpec(
        "hero-incomplete",
        num,
        "high",
        bb,
        "Hero section incomplete",
        `Hero is missing: ${missing.join(", ")}. Visitors need a clear value proposition and next action above the fold to convert.`,
        "Incomplete hero section reduces above-fold conversion",
        `Add ${missing.join(" and ")} to the hero section`,
      ));
    } else {
      add(makeSpec(
        "hero-strong",
        num,
        "positive",
        bb,
        "Strong hero section",
        "Hero has headline, subheadline, and CTA — strong above-fold composition supporting conversion.",
        null,
        null,
      ));
    }
  }

  // ── CTAs ──────────────────────────────────────────────────────────────────
  if (detected.ctaCount === 0) {
    add(makeSpec(
      "no-cta",
      num,
      "critical",
      makeBB(0, 0, 1280, 720),
      "No clear CTA visible",
      "No action-oriented buttons or links detected on this page. Visitors have no guided next step, severely reducing conversion.",
      "Missing conversion pathway",
      "Add at least one prominent CTA above the fold",
    ));
  } else if (detected.ctaCountInViewport === 0 && detected.ctaCount > 0) {
    add(makeSpec(
      "cta-below-fold",
      num,
      "high",
      makeBB(0, 600, 1280, 120),
      "CTAs below the fold",
      `${detected.ctaCount} CTA(s) detected but none visible without scrolling. Above-fold CTAs convert significantly better.`,
      "Below-fold conversion pathway",
      "Move primary CTA above the fold",
    ));
  } else if (detected.primaryCTAs.every((c) => /learn more|click here|read more/i.test(c.text))) {
    add(makeSpec(
      "generic-cta",
      num,
      "moderate",
      detected.primaryCTAs[0]?.boundingBox ?? makeBB(300, 200, 680, 60),
      "Generic CTAs reduce conversion",
      `CTAs use vague language ("${detected.primaryCTAs[0]?.text ?? "Learn More"}"). Action-specific text ("Get a Free Quote", "Book Now") converts 15-25% better.`,
      "Weak call-to-action language",
      "Replace generic CTAs with specific action-oriented text",
    ));
  }

  // ── FAQ ───────────────────────────────────────────────────────────────────
  if (!detected.hasFAQAccordion) {
    add(makeSpec(
      "no-faq",
      num,
      "high",
      makeBB(0, 400, 1280, 200),
      "Missing FAQ section",
      "No FAQ content detected. FAQ sections capture long-tail queries, improve time-on-page, and enable FAQ schema for rich results.",
      "Missing FAQ content",
      "Add FAQ section with 5-8 relevant customer questions",
    ));
  } else if (!detected.hasFAQAccordionInViewport) {
    add(makeSpec(
      "faq-below-fold",
      num,
      "moderate",
      detected.faqAccordionBoundingBox ?? makeBB(0, 500, 1280, 150),
      "FAQ not above the fold",
      "FAQ content exists but is not visible above the fold. Moving it higher captures attention earlier and addresses objections sooner.",
      null,
      "Move FAQ section higher on the page",
    ));
  }

  // ── Review widgets ────────────────────────────────────────────────────────
  if (!detected.hasReviewWidget) {
    add(makeSpec(
      "no-social-proof",
      num,
      "high",
      makeBB(0, 400, 1280, 120),
      "No visible social proof",
      "No star ratings, testimonials, or review widgets detected. Social proof is a primary trust signal and conversion driver, especially for service businesses.",
      "Missing social proof",
      "Add star rating widget or testimonial block prominently above the fold",
    ));
  }

  // ── Trust badges ──────────────────────────────────────────────────────────
  if (!detected.hasTrustBadges) {
    add(makeSpec(
      "no-trust-badges",
      num,
      "moderate",
      makeBB(0, 600, 1280, 80),
      "Missing trust signals",
      "No certifications, awards, or guarantee badges detected. Trust signals reduce purchase friction, especially for high-value services.",
      null,
      "Add certification badges, guarantees, or professional memberships",
    ));
  }

  // ── Heading hierarchy ─────────────────────────────────────────────────────
  if (detected.multipleH1s) {
    add(makeSpec(
      "multiple-h1",
      num,
      "high",
      detected.headingHierarchy.find((h) => h.level === 1)?.boundingBox ?? makeBB(0, 50, 900, 60),
      "Multiple H1s",
      `${detected.headingHierarchy.filter((h) => h.level === 1).length} H1 tags detected. Search engines expect exactly one H1 as the primary page topic signal.`,
      "Multiple H1 tags confuse crawlers",
      "Consolidate to a single H1 tag per page",
    ));
  } else if (!detected.hasH1) {
    add(makeSpec(
      "no-h1",
      num,
      "high",
      makeBB(0, 50, 1280, 80),
      "No H1 tag",
      "No H1 heading detected on this page. H1 is a critical on-page relevance signal for both search engines and visitors.",
      "Missing H1 tag",
      "Add a descriptive H1 tag matching the page's primary keyword target",
    ));
  }

  // ── Images without alt ────────────────────────────────────────────────────
  if (detected.imagesWithoutAlt > 5) {
    add(makeSpec(
      "images-no-alt",
      num,
      "moderate",
      makeBB(0, 200, 1280, 400),
      "Images missing alt text",
      `${detected.imagesWithoutAlt} image(s) detected without alt attributes. Alt text provides accessibility compliance and search engine context for image content.`,
      "Missing image alt text",
      "Add descriptive alt text to all meaningful images",
    ));
  }

  // ── Schema visible but not in markup ─────────────────────────────────────
  if (
    detected.visibleSchemaIndicators.some((i) => i.indicatorType === "star-ratings") &&
    !brandContext.hasSchemaDetected
  ) {
    add(makeSpec(
      "star-no-schema",
      num,
      "moderate",
      detected.visibleSchemaIndicators[0]?.boundingBox ?? makeBB(20, 480, 300, 40),
      "Star ratings missing schema",
      "Star ratings visible on page but no AggregateRating schema detected in markup. Adding schema enables rich result star snippets in search results.",
      "Missing AggregateRating schema",
      "Add AggregateRating schema markup to match visible star ratings",
    ));
  }

  // ── Local/healthcare/restaurant vertical rules ────────────────────────────
  if (LOCAL_VERTICALS.has(industryVertical)) {
    const hasPhone = /tel:|(\+1[\s.-]?)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}/.test(
      detected.primaryCTAs.map((c) => c.text + c.ctaType).join(" "),
    );
    if (!hasPhone && detected.ctaCountInViewport === 0) {
      add(makeSpec(
        "no-phone-visible",
        num,
        "high",
        makeBB(800, 0, 480, 80),
        "Phone number not prominent",
        "No phone number detected above the fold. For local service businesses, a prominent phone number is the #1 conversion driver.",
        "Phone number not visible above the fold",
        "Add click-to-call phone number in the header navigation",
      ));
    }

    const hasAddress = /\d+\s+\w+\s+(street|st|avenue|ave|road|rd|blvd|lane|ln|drive|dr)/i.test(
      detected.headingHierarchy.map((h) => h.text).join(" "),
    );
    if (!hasAddress && !brandContext.hasLocalSchema) {
      add(makeSpec(
        "no-location",
        num,
        "moderate",
        makeBB(0, 600, 1280, 80),
        "Location info missing",
        "No visible address or location information detected. Local service businesses need visible location signals for local search intent.",
        "Missing location information",
        "Add service area or physical address near the header or footer",
      ));
    }
  }

  // ── E-commerce vertical rules ─────────────────────────────────────────────
  if (ECOMMERCE_VERTICALS.has(industryVertical)) {
    const hasPrice = detected.visibleSchemaIndicators.some((i) => i.indicatorType === "price-display");
    if (!hasPrice) {
      add(makeSpec(
        "no-price",
        num,
        "high",
        makeBB(0, 200, 1280, 300),
        "Price not displayed",
        "No visible pricing detected. Shoppers expect to see prices without navigating to a product page; absence increases bounce rates.",
        "Pricing not visible",
        "Display prices prominently on category and product pages",
      ));
    }
  }

  // ── B2B SaaS vertical rules ───────────────────────────────────────────────
  if (B2B_VERTICALS.has(industryVertical)) {
    const hasPricingCTA = detected.primaryCTAs.some((c) =>
      /pricing|demo|trial|start free/i.test(c.text),
    );
    if (!hasPricingCTA) {
      add(makeSpec(
        "no-b2b-path",
        num,
        "critical",
        makeBB(0, 0, 1280, 720),
        "Pricing/Demo path missing",
        "No visible pricing page link or demo CTA detected. B2B buyers require a clear pricing or evaluation path; its absence is a leading cause of SaaS bounce.",
        "B2B conversion path not visible",
        "Add prominent 'View Pricing' and 'Request Demo' CTAs in the hero and navigation",
      ));
    }

    const hasClientProof = /case study|client|customer logo|trusted by|used by/i.test(
      detected.headingHierarchy.map((h) => h.text).join(" "),
    );
    if (!hasClientProof && !detected.hasReviewWidget) {
      add(makeSpec(
        "no-b2b-social-proof",
        num,
        "high",
        makeBB(0, 300, 1280, 200),
        "No B2B social proof",
        "No client logos, case studies, or testimonials detected. B2B buyers require vendor credibility signals before engaging sales.",
        "Missing B2B social proof",
        "Add customer logos, case study links, or G2/Capterra review widget",
      ));
    }
  }

  // ── Positive: excellent above-fold composition ────────────────────────────
  if (
    detected.hasFAQAccordionInViewport &&
    detected.ctaCountInViewport > 0 &&
    detected.hasReviewWidget &&
    specs.filter((s) => s.severity === "positive").length === 0
  ) {
    add(makeSpec(
      "excellent-composition",
      num,
      "positive",
      makeBB(0, 0, 1280, 720),
      "Excellent above-fold layout",
      "FAQ, CTA, and review widget all visible above the fold — strong conversion-optimized composition that supports both user intent and AI citability.",
      null,
      null,
    ));
  }

  return specs.slice(0, 8);
}
