/**
 * GET /api/site-tag/audit-overlay?siteId=xxx&pageUrl=/about
 *
 * Called by the meSEO Site Tag (public/t.js) on a customer's live page when
 * the audit overlay is activated via ?meseo_audit=true. Returns ALL issues
 * for the specific page from the latest completed technical audit, plus any
 * page-level issues (missing meta description, missing H1, etc.) that aren't
 * pinned to a specific element.
 *
 * Auth model mirrors /api/site-tag/issue-evidence: no user auth required —
 * the siteId acts as the shared secret (same pattern used for event collection).
 *
 * Response shape:
 *   {
 *     enabled: boolean,
 *     page: string,
 *     issues: OverlayIssue[],
 *     summary: { total, critical, warnings, info }
 *   }
 */

import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { mapIssueForOverlay, type OverlayIssue } from "@/lib/services/issue-selector";
import { getCorsHeaders } from "@/lib/services/page-lifecycle";

export const dynamic = "force-dynamic";

export async function OPTIONS(req: Request) {
  return new NextResponse(null, { status: 204, headers: getCorsHeaders(req) });
}

export async function GET(req: Request) {
  const cors = getCorsHeaders(req);
  const { searchParams } = new URL(req.url);
  const siteId = searchParams.get("siteId");
  const pageUrl = searchParams.get("pageUrl") ?? "/";

  if (!siteId) {
    return NextResponse.json(
      { enabled: false, error: "siteId required" },
      { status: 400, headers: cors },
    );
  }

  // Verify the siteId matches an active TrackedSite
  const site = await prisma.trackedSite.findFirst({
    where: { siteId, status: "active" },
    select: { id: true, brandId: true, allowedDomains: true },
  });

  if (!site) {
    return NextResponse.json(
      { enabled: false, error: "Site not found or inactive" },
      { status: 404, headers: cors },
    );
  }

  // Load the latest completed audit for this brand
  const audit = await prisma.technicalAudit.findFirst({
    where: { brandId: site.brandId, status: "completed" },
    orderBy: { completedAt: "desc" },
    select: { id: true, completedAt: true },
  });

  if (!audit) {
    return NextResponse.json({
      enabled: true,
      page: pageUrl,
      issues: [],
      summary: { total: 0, critical: 0, warnings: 0, info: 0 },
      noAudit: true,
    }, { headers: cors });
  }

  // Fetch all open issues from this audit. We filter to the specific page
  // below using both pageUrl and affectedUrls — a single issue can have
  // multiple affected URLs when the crawler finds it on many pages.
  const allIssues = await prisma.technicalIssue.findMany({
    where: { auditId: audit.id, status: "open" },
    select: {
      id: true,
      title: true,
      category: true,
      severity: true,
      detail: true,
      pageUrl: true,
      affectedUrls: true,
      evidence: true,
    },
    orderBy: [{ severity: "asc" }, { category: "asc" }],
  });

  // Normalise the incoming page URL: strip trailing slash, lowercase host.
  // Supports both path-only ("/about") and full URL ("https://example.com/about").
  const normalisedPage = normalisePath(pageUrl);

  const matchedIssues: OverlayIssue[] = [];
  for (const issue of allIssues) {
    if (!issueMatchesPage(issue, normalisedPage)) continue;
    // mapIssueForOverlay explodes one TechnicalIssue row into multiple
    // OverlayIssue entries — one per affected element (evidence item).
    const mapped = mapIssueForOverlay(issue, pageUrl);
    for (const m of mapped) matchedIssues.push(m);
  }

  const summary = {
    total: matchedIssues.length,
    critical: matchedIssues.filter(i => i.severity === "critical").length,
    warnings: matchedIssues.filter(i => i.severity === "high" || i.severity === "medium").length,
    info: matchedIssues.filter(i => i.severity === "low" || i.severity === "info").length,
  };

  return NextResponse.json({
    enabled: true,
    page: pageUrl,
    issues: matchedIssues,
    summary,
  }, { headers: cors });
}

// ─── Path matching helpers ──────────────────────────────────────────────────

function normalisePath(input: string): string {
  try {
    const url = new URL(input);
    return url.pathname.replace(/\/$/, "") || "/";
  } catch {
    return input.replace(/\/$/, "") || "/";
  }
}

type IssueRow = {
  pageUrl: string | null;
  affectedUrls: unknown;
};

/**
 * Return true if the issue affects the requested page. Checks both the
 * issue.pageUrl field AND any URL in the affectedUrls JSON array. Page-level
 * issues (missing_meta_description, missing_h1, etc.) where pageUrl is null
 * AND affectedUrls is empty are NOT matched — we only show issues that
 * explicitly list this page as affected.
 */
function issueMatchesPage(issue: IssueRow, normalisedPage: string): boolean {
  const candidates: string[] = [];
  if (issue.pageUrl) candidates.push(issue.pageUrl);
  if (Array.isArray(issue.affectedUrls)) {
    for (const u of issue.affectedUrls) {
      if (typeof u === "string") candidates.push(u);
    }
  }

  // If the issue has no page context at all, it's a site-wide issue that
  // shouldn't be highlighted on any specific page.
  if (candidates.length === 0) return false;

  return candidates.some(c => normalisePath(c) === normalisedPage);
}
