"use client";

import { useState, useMemo, useEffect, useCallback } from "react";
import { AlertTriangle, Search, X, CheckCircle2, Clock, Circle, ArrowRight, Link2, Wrench, ChevronRight, TrendingDown, Download, Shield, ShieldAlert, RotateCcw, Eye, Ghost, Link as LinkIcon } from "lucide-react";
import { useBrand } from "@/context/brand-context";
import { useBackgroundTasks } from "@/lib/stores/task-store";
import { SourceEmptyState } from "@/components/source-empty-state";

type Priority = "High" | "Medium" | "Low";
type Status = "Open" | "In Progress" | "Resolved";

type TabId = "404" | "broken" | "orphan";

interface SourceLink { page: string; anchorText: string }

interface BrokenInternalLink {
  sourceUrl: string;
  destinationUrl: string;
  linkText: string;
  elementType: string;
  selector: string;
  parentSection: string;
  statusCode: number;
  detectedAt: string;
}

interface OrphanPage {
  url: string;
  fullUrl: string;
  title?: string | null;
  gscClicks: number;
  gscImpressions: number;
  visits: number;
  isInNav: boolean;
  recommendation: string;
}

interface DeadPage {
  id: number;
  deadUrl: string;
  sources: SourceLink[];
  suggestedFix: string;
  fixType: "Redirect" | "Remove" | "Recreate";
  priority: Priority;
  status: Status;
  discovered: string;
  whyItMatters: string;
}

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

const priorityStyle: Record<Priority, string> = {
  High:   "bg-red-50 text-red-700 border-red-200",
  Medium: "bg-amber-50 text-amber-700 border-amber-200",
  Low:    "bg-slate-100 text-slate-600 border-slate-200",
};

const statusConfig: Record<Status, { style: string; icon: React.ReactNode }> = {
  "Open":        { style: "bg-red-50 text-red-600 border-red-200",     icon: <Circle className="w-3 h-3" /> },
  "In Progress": { style: "bg-amber-50 text-amber-700 border-amber-200", icon: <Clock className="w-3 h-3" /> },
  "Resolved":    { style: "bg-green-50 text-green-700 border-green-200", icon: <CheckCircle2 className="w-3 h-3" /> },
};

const fixTypeStyle: Record<string, string> = {
  Redirect: "bg-blue-50 text-blue-700",
  Remove:   "bg-slate-100 text-slate-600",
  Recreate: "bg-purple-50 text-purple-700",
};

function PriorityBadge({ p }: { p: Priority }) {
  return <span className={`text-[10px] font-bold uppercase tracking-wide px-1.5 py-0.5 rounded border ${priorityStyle[p]}`}>{p}</span>;
}

function StatusBadge({ s }: { s: Status }) {
  const { style, icon } = statusConfig[s];
  return (
    <span className={`inline-flex items-center gap-1 text-[10px] font-semibold px-1.5 py-0.5 rounded border ${style}`}>
      {icon}{s}
    </span>
  );
}

const PRIORITY_WEIGHT: Record<Priority, number> = { High: 3, Medium: 2, Low: 1 };

function impactScore(page: DeadPage): number {
  return page.sources.length * PRIORITY_WEIGHT[page.priority];
}

function ImpactDot({ score }: { score: number }) {
  const color = score >= 9 ? "bg-red-500" : score >= 4 ? "bg-amber-400" : "bg-slate-300";
  return <span className={`w-2 h-2 rounded-full ${color} shrink-0`} title={`Impact: ${score}`} />;
}

// ─── Page ─────────────────────────────────────────────────────────────────────

function capitalize(s: string): string { return s ? s.charAt(0).toUpperCase() + s.slice(1) : ""; }

export default function BrokenLinksPage() {
  const { brand, getSourceStatus } = useBrand();
  const { addTask, completeTask, failTask } = useBackgroundTasks();
  const sourceStatus = getSourceStatus("dead_pages");

  const [pages, setPages] = useState<DeadPage[]>([]);
  const [query, setQuery]       = useState("");
  const [filter, setFilter]     = useState<Priority | "All">("All");
  const [selected, setSelected] = useState<DeadPage | null>(null);
  const [statuses, setStatuses] = useState<Record<number, Status>>({});
  const [scanning, setScanning] = useState(false);
  const [scanError, setScanError] = useState<string | null>(null);
  const [scanFailure, setScanFailure] = useState<{
    reason: "blocked" | "timeout" | "network" | "not_found" | "unknown";
    homepageStatus?: number;
  } | null>(null);
  const [scanSource, setScanSource] = useState<"fetch" | "headless" | "site_tag" | null>(null);

  // ── Tabs: 404 (dead pages), broken (internal links), orphan (unlinked) ──
  const [tab, setTab] = useState<TabId>("404");
  const [brokenLinks, setBrokenLinks] = useState<BrokenInternalLink[]>([]);
  const [orphanPages, setOrphanPages] = useState<OrphanPage[]>([]);
  const [brokenLoading, setBrokenLoading] = useState(false);
  const [orphanLoading, setOrphanLoading] = useState(false);

  // Load broken internal links + orphan counts up-front so the tab
  // badges can show totals even before the user switches tabs.
  const loadBrokenLinks = useCallback(async () => {
    setBrokenLoading(true);
    try {
      const res = await fetch(`/api/dead-pages?brandId=${brand.id}&type=broken`);
      if (!res.ok) { setBrokenLinks([]); return; }
      const data = await res.json();
      setBrokenLinks(Array.isArray(data?.brokenLinks) ? data.brokenLinks : []);
    } catch { setBrokenLinks([]); }
    finally { setBrokenLoading(false); }
  }, [brand.id]);

  const loadOrphanPages = useCallback(async () => {
    setOrphanLoading(true);
    try {
      const res = await fetch(`/api/dead-pages?brandId=${brand.id}&type=orphan`);
      if (!res.ok) { setOrphanPages([]); return; }
      const data = await res.json();
      setOrphanPages(Array.isArray(data?.orphanPages) ? data.orphanPages : []);
    } catch { setOrphanPages([]); }
    finally { setOrphanLoading(false); }
  }, [brand.id]);

  useEffect(() => { loadBrokenLinks(); loadOrphanPages(); }, [loadBrokenLinks, loadOrphanPages]);

  const loadDeadPages = useCallback(async () => {
    try {
      const res = await fetch(`/api/dead-pages?brandId=${brand.id}`);
      if (!res.ok) return;
      const data = await res.json();
      if (!Array.isArray(data) || data.length === 0) return;

      const mapped: DeadPage[] = data.map((d: Record<string, unknown>, i: number) => ({
        id: i + 1,
        deadUrl: d.deadUrl as string,
        sources: ((d.sources as Array<Record<string, string>>) ?? []).map((s) => ({
          page: s.sourceUrl ?? "",
          anchorText: s.anchorText ?? "",
        })),
        suggestedFix: (d.suggestedFix as string) || `Redirect ${d.deadUrl as string} to a relevant live page`,
        fixType: "Redirect" as const,
        priority: capitalize(d.priority as string) as Priority,
        status: capitalize(d.status as string) === "Open" ? "Open" as const : d.status === "fixed" ? "Resolved" as const : "Open" as const,
        discovered: new Date(d.discoveredAt as string).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }),
        whyItMatters: `This broken page has ${((d.sources as Array<unknown>) ?? []).length} inbound link(s) sending users to a 404 error.`,
      }));

      setPages(mapped);
      setSelected(mapped[0] ?? null);
      setStatuses(Object.fromEntries(mapped.map((d) => [d.id, d.status])));
    } catch { /* network error */ }
  }, [brand.id]);

  useEffect(() => { loadDeadPages(); }, [loadDeadPages]);

  // ── Derived state ──────────────────────────────────────────────
  // These hooks MUST sit above the conditional early returns below.
  // The page previously called useMemo for `filtered` AFTER two
  // conditional `return` blocks, which violates the Rules of Hooks
  // — when `pages` shifted from empty → populated React saw a
  // different hook count and crashed with "Application error: a
  // client-side exception has occurred." Moving the derivation up
  // here guarantees the same hook sequence on every render.
  const filtered = useMemo(() => pages.filter((d) => {
    const matchesPriority = filter === "All" || d.priority === filter;
    const q = query.toLowerCase();
    const matchesQuery = !q || d.deadUrl.includes(q) || d.sources.some(s => s.page.includes(q) || s.anchorText.toLowerCase().includes(q));
    return matchesPriority && matchesQuery;
  }).sort((a, b) => impactScore(b) - impactScore(a)), [query, filter, pages]);

  async function triggerScan() {
    setScanning(true);
    setScanError(null);
    setScanFailure(null);
    setScanSource(null);
    const taskId = addTask({ id: `dead_${Date.now()}`, type: "dead_page_scan", label: "Scanning for Dead Pages...", brandId: brand.id, resultUrl: "/broken-links" });
    try {
      const res = await fetch("/api/dead-pages/run", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ brandId: brand.id }),
      });
      const data = await res.json();
      if (data.status === "completed") {
        setScanSource(data.discoverySource ?? null);
        await loadDeadPages();
        completeTask(taskId, { resultUrl: "/broken-links", resultSummary: "Dead page scan complete" });
      } else {
        setScanError(data.message || "Scan failed");
        if (data.failureReason) {
          setScanFailure({ reason: data.failureReason, homepageStatus: data.homepageStatus });
        }
        failTask(taskId, data.message || "Scan failed");
      }
    } catch {
      // Raw fetch failure (offline, DNS, CORS, etc.). The error banner
      // below gates on `scanFailure` being set — without it, scanError
      // lands in state but nothing renders, so the scan spinner simply
      // stops and the user has no idea what happened. Populate
      // scanFailure with reason="network" so the existing banner path
      // picks it up and the "Unable to scan — network error" copy
      // appears with a Retry button.
      setScanError("Network error");
      setScanFailure({ reason: "network" });
      failTask(taskId, "Network error");
    }
    setScanning(false);
  }

  // Navigate to the visual inspector for a given source URL. Used by
  // the "Preview" buttons on the Broken Internal Links tab. We open in
  // a new tab so the list of broken links stays open for reference.
  function openPreview(sourcePath: string) {
    const host = brand.domain.replace(/^https?:\/\//, "").replace(/\/+$/, "");
    const targetUrl = `https://${host}${sourcePath}`;
    window.open(
      `/preview?url=${encodeURIComponent(targetUrl)}&brandId=${encodeURIComponent(brand.id)}`,
      "_blank",
      "noopener,noreferrer",
    );
  }

  // Shared tab bar — rendered above every state of this page so users
  // can switch between the three views even when the 404 tab is empty.
  const tabBar = (
    <div className="flex flex-wrap gap-2">
      {([
        { id: "404",    label: "404 Pages",            icon: <AlertTriangle className="w-3.5 h-3.5" />, count: pages.length },
        { id: "broken", label: "Broken Internal Links", icon: <LinkIcon className="w-3.5 h-3.5" />,      count: brokenLinks.length },
        { id: "orphan", label: "Orphan Pages",          icon: <Ghost className="w-3.5 h-3.5" />,         count: orphanPages.length },
      ] as const).map((t) => {
        const active = tab === t.id;
        return (
          <button
            key={t.id}
            onClick={() => setTab(t.id)}
            className={`inline-flex items-center gap-2 px-3.5 py-2 rounded-lg text-xs font-semibold border transition-colors ${
              active
                ? "bg-slate-900 text-white border-slate-900"
                : "bg-white text-slate-600 border-slate-200 hover:bg-slate-50"
            }`}
          >
            {t.icon}
            {t.label}
            <span
              className={`ml-1 text-[10px] font-bold px-1.5 py-0.5 rounded ${
                active ? "bg-white/20 text-white" : "bg-slate-100 text-slate-600"
              }`}
            >
              {t.count}
            </span>
          </button>
        );
      })}
    </div>
  );

  const pageHeader = (
    <div>
      <h1 className="text-2xl font-bold text-slate-900">Broken Links</h1>
      <p className="text-slate-500 text-sm mt-1">
        404 pages, broken internal links, and orphan pages on{" "}
        <span className="font-medium text-slate-700">{brand.domain}</span>.
      </p>
    </div>
  );

  // ── Tab: Broken Internal Links ───────────────────────────────────────────
  if (tab === "broken") {
    return (
      <div className="space-y-5">
        {pageHeader}
        {tabBar}
        <BrokenInternalLinksTab
          links={brokenLinks}
          loading={brokenLoading}
          onReload={loadBrokenLinks}
          onPreview={openPreview}
        />
      </div>
    );
  }

  // ── Tab: Orphan Pages ────────────────────────────────────────────────────
  if (tab === "orphan") {
    return (
      <div className="space-y-5">
        {pageHeader}
        {tabBar}
        <OrphanPagesTab pages={orphanPages} loading={orphanLoading} onReload={loadOrphanPages} />
      </div>
    );
  }

  // ── Tab: 404 Pages (existing behaviour) ──────────────────────────────────
  const hasDeadPageData = sourceStatus && (sourceStatus.status === "connected" || sourceStatus.status === "completed" || sourceStatus.status === "stale" || sourceStatus.status === "partial_failure");
  if (pages.length === 0 && !hasDeadPageData) {
    // ── Blocked / failed scan card ──
    // Renders when the backend cascade (fetch → headless → Site Tag)
    // all failed. Copy is tailored to the specific failure reason so
    // the user knows whether to allowlist a WAF rule, wait for the
    // site to come back up, or install the Site Tag.
    if (scanFailure && !scanning) {
      const statusHint = scanFailure.homepageStatus ? ` (HTTP ${scanFailure.homepageStatus})` : "";
      const title =
        scanFailure.reason === "blocked" ? `Unable to scan — the website is blocking automated access${statusHint}`
        : scanFailure.reason === "timeout" ? "Unable to scan — the website took too long to respond"
        : scanFailure.reason === "network" ? "Unable to scan — network error reaching the website"
        : "Unable to scan — the website returned an unexpected response";

      return (
        <div className="space-y-6 max-w-5xl">
          {pageHeader}
          {tabBar}
          <div className="bg-white rounded-xl border border-red-200 p-8">
            <div className="flex items-start gap-4">
              <div className="w-12 h-12 rounded-xl bg-red-50 border border-red-200 flex items-center justify-center shrink-0">
                <ShieldAlert className="w-6 h-6 text-red-500" />
              </div>
              <div className="flex-1 min-w-0">
                <h2 className="text-lg font-bold text-slate-900 mb-1">{title}</h2>
                <p className="text-sm text-slate-600 mb-4">{scanError}</p>

                {scanFailure.reason === "blocked" && (
                  <div className="bg-amber-50 border border-amber-200 rounded-lg p-4 mb-4 text-sm text-amber-900 space-y-2">
                    <p className="font-semibold">How to fix this:</p>
                    <ul className="list-disc list-inside space-y-1 text-amber-800">
                      <li>If your site uses Cloudflare or another WAF, whitelist the User-Agent <code className="bg-white px-1 rounded border border-amber-200 text-[11px]">meSEO/1.0</code>.</li>
                      <li>Or install the <a href="/site-tag" className="font-semibold underline hover:text-amber-700">meSEO Site Tag</a> — the scanner will use its collected link map to bypass bot protection entirely.</li>
                      <li>Check if the site has a custom firewall rule blocking server-to-server requests.</li>
                    </ul>
                  </div>
                )}

                {scanFailure.reason === "timeout" && (
                  <p className="text-xs text-slate-500 mb-4">
                    The homepage didn&apos;t respond within 15 seconds. Try again in a moment, or check if the site is currently up.
                  </p>
                )}

                <button
                  onClick={triggerScan}
                  disabled={scanning}
                  className="inline-flex items-center gap-2 px-5 py-2.5 bg-brand-600 text-white text-sm font-semibold rounded-xl hover:bg-brand-700 disabled:opacity-50 transition-colors"
                >
                  <RotateCcw className="w-4 h-4" />
                  Retry Scan
                </button>
              </div>
            </div>
          </div>
        </div>
      );
    }

    // ── Normal empty state (never scanned, or scan completed with zero results) ──
    return (
      <div className="space-y-6 max-w-5xl">
        {pageHeader}
        {tabBar}
        <div className="bg-white rounded-xl border border-slate-200 p-8 text-center">
          <Shield className="w-12 h-12 text-slate-200 mx-auto mb-3" />
          <h2 className="text-lg font-bold text-slate-900 mb-2">
            {scanning ? "Scanning..." : "No Dead Pages Found"}
          </h2>
          <p className="text-sm text-slate-500 max-w-md mx-auto mb-4">
            {scanning
              ? "Crawling your site for broken links — this may take 30-60 seconds."
              : "Run a scan to discover broken internal links returning 404 errors."}
          </p>
          {scanSource === "site_tag" && (
            <p className="text-[11px] font-semibold text-brand-600 mb-2">Scan powered by meSEO Site Tag</p>
          )}
          <button
            onClick={triggerScan}
            disabled={scanning}
            className="px-6 py-3 bg-brand-600 text-white text-sm font-semibold rounded-xl hover:bg-brand-700 disabled:opacity-50 transition-colors"
          >
            {scanning ? "Scanning..." : "Scan for Dead Pages"}
          </button>
        </div>
      </div>
    );
  }

  // `filtered` is already derived above the early-returns for hook
  // safety; counts + impact metrics can live inline since they're
  // not hooks.
  const counts = {
    total: pages.length,
    high:  pages.filter(d => d.priority === "High").length,
    open:  pages.filter(d => statuses[d.id] === "Open").length,
    resolved: pages.filter(d => statuses[d.id] === "Resolved").length,
  };

  // Impact metrics
  const openPages = pages.filter(d => statuses[d.id] !== "Resolved");
  const totalBrokenLinks = openPages.reduce((sum, d) => sum + d.sources.length, 0);
  const estMonthlyLoss = openPages.reduce((sum, d) => sum + d.sources.length * PRIORITY_WEIGHT[d.priority] * 45, 0);
  const highOpenCount = openPages.filter(d => d.priority === "High").length;
  const redirectableCount = openPages.filter(d => d.fixType === "Redirect").length;

  // Bulk actions
  function bulkRedirectHighPriority() {
    setStatuses(prev => {
      const next = { ...prev };
      pages.forEach(d => { if (d.priority === "High" && prev[d.id] === "Open") next[d.id] = "In Progress"; });
      return next;
    });
  }

  function bulkApplyAllFixes() {
    setStatuses(prev => {
      const next = { ...prev };
      pages.forEach(d => { if (prev[d.id] !== "Resolved") next[d.id] = "In Progress"; });
      return next;
    });
  }

  function exportCsv() {
    const header = "URL,Priority,Status,Fix Type,Suggested Fix,Sources,Discovered";
    const rows = pages.map(d =>
      `"${d.deadUrl}","${d.priority}","${statuses[d.id]}","${d.fixType}","${d.suggestedFix}","${d.sources.length}","${d.discovered}"`
    );
    const blob = new Blob([header + "\n" + rows.join("\n")], { type: "text/csv" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url; a.download = "dead-pages-report.csv"; a.click();
    URL.revokeObjectURL(url);
  }

  function cycleStatus(id: number) {
    const order: Status[] = ["Open", "In Progress", "Resolved"];
    setStatuses(prev => {
      const next = order[(order.indexOf(prev[id]) + 1) % 3];
      return { ...prev, [id]: next };
    });
  }

  const sel = selected ? { ...selected, status: statuses[selected.id] } : null;

  return (
    <div className="space-y-5">

      {/* ── Header ── */}
      <div className="flex items-start justify-between">
        {pageHeader}
        <span className="hidden sm:inline-flex items-center gap-1.5 text-xs text-slate-400 bg-slate-50 border border-slate-200 px-3 py-1.5 rounded-full whitespace-nowrap">
          Last crawled: <span className="font-medium text-slate-600">Today, 9:14 am</span>
        </span>
      </div>

      {tabBar}

      {/* ── Impact Summary ── */}
      {openPages.length > 0 && (
        <div className="bg-gradient-to-r from-red-50 via-amber-50 to-orange-50 rounded-xl border border-red-200/60 px-5 py-4">
          <div className="flex items-center gap-2 mb-3">
            <div className="w-7 h-7 rounded-lg bg-red-100 flex items-center justify-center">
              <TrendingDown className="w-4 h-4 text-red-600" />
            </div>
            <div>
              <h2 className="text-sm font-bold text-slate-900">Impact Summary</h2>
              <p className="text-[11px] text-slate-500">{openPages.length} unresolved page{openPages.length !== 1 ? "s" : ""} actively hurting your site</p>
            </div>
          </div>
          <div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
            <div className="bg-white/80 rounded-lg px-3 py-2.5 border border-red-100">
              <p className="text-[10px] font-semibold text-slate-400 uppercase tracking-wide">Est. Monthly Loss</p>
              <p className="text-xl font-bold text-red-600 mt-0.5">~{estMonthlyLoss.toLocaleString()}</p>
              <p className="text-[10px] text-slate-400">visits lost to 404s</p>
            </div>
            <div className="bg-white/80 rounded-lg px-3 py-2.5 border border-amber-100">
              <p className="text-[10px] font-semibold text-slate-400 uppercase tracking-wide">Broken Links</p>
              <p className="text-xl font-bold text-amber-600 mt-0.5">{totalBrokenLinks}</p>
              <p className="text-[10px] text-slate-400">internal links wasted</p>
            </div>
            <div className="bg-white/80 rounded-lg px-3 py-2.5 border border-red-100">
              <p className="text-[10px] font-semibold text-slate-400 uppercase tracking-wide">High Priority</p>
              <p className="text-xl font-bold text-red-600 mt-0.5">{highOpenCount}</p>
              <p className="text-[10px] text-slate-400">need immediate action</p>
            </div>
            <div className="bg-white/80 rounded-lg px-3 py-2.5 border border-blue-100">
              <p className="text-[10px] font-semibold text-slate-400 uppercase tracking-wide">Quick Wins</p>
              <p className="text-xl font-bold text-blue-600 mt-0.5">{redirectableCount}</p>
              <p className="text-[10px] text-slate-400">fixable via 301 redirect</p>
            </div>
          </div>
        </div>
      )}

      {/* ── Stat strip ── */}
      <div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
        {[
          { label: "Total Dead", value: counts.total, style: "text-slate-900" },
          { label: "High Priority", value: counts.high, style: "text-red-600" },
          { label: "Still Open", value: counts.open, style: "text-amber-600" },
          { label: "Resolved", value: counts.resolved, style: "text-green-600" },
        ].map(s => (
          <div key={s.label} className="bg-white rounded-xl border border-slate-200 px-4 py-4">
            <p className="text-xs font-semibold text-slate-400 uppercase tracking-wide">{s.label}</p>
            <p className={`text-3xl font-bold mt-1 ${s.style}`}>{s.value}</p>
          </div>
        ))}
      </div>

      {/* ── Bulk Actions ── */}
      <div className="bg-white rounded-xl border border-slate-200 px-4 py-3 flex flex-wrap items-center gap-2">
        <span className="text-xs font-semibold text-slate-500 mr-1">Bulk Actions</span>
        <button onClick={bulkRedirectHighPriority}
          className="inline-flex items-center gap-1.5 text-xs font-semibold px-3 py-1.5 rounded-lg bg-red-600 text-white hover:bg-red-700 transition-colors">
          <Shield className="w-3 h-3" />
          Redirect All High Priority ({highOpenCount})
        </button>
        <button onClick={bulkApplyAllFixes}
          className="inline-flex items-center gap-1.5 text-xs font-semibold px-3 py-1.5 rounded-lg bg-brand-600 text-white hover:bg-brand-700 transition-colors">
          <RotateCcw className="w-3 h-3" />
          Apply All Fixes ({openPages.length})
        </button>
        <button onClick={exportCsv}
          className="inline-flex items-center gap-1.5 text-xs font-semibold px-3 py-1.5 rounded-lg border border-slate-200 text-slate-600 hover:bg-slate-50 transition-colors">
          <Download className="w-3 h-3" />
          Export CSV
        </button>
      </div>

      {/* ── Search + filter ── */}
      <div className="bg-white rounded-xl border border-slate-200 px-4 py-3 flex flex-col sm:flex-row gap-3 items-start sm:items-center">
        <div className="relative flex-1 w-full">
          <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400 pointer-events-none" />
          <input
            type="text" placeholder="Search URL, source page, anchor text…"
            value={query} onChange={e => setQuery(e.target.value)}
            className="w-full pl-9 pr-8 py-2 text-sm bg-slate-50 border border-slate-200 rounded-lg placeholder-slate-400 text-slate-800 focus:outline-none focus:ring-2 focus:ring-brand-500 transition"
          />
          {query && <button onClick={() => setQuery("")} className="absolute right-2.5 top-1/2 -translate-y-1/2 text-slate-400 hover:text-slate-600"><X className="w-3.5 h-3.5" /></button>}
        </div>
        <div className="flex items-center gap-2">
          {(["All", "High", "Medium", "Low"] as const).map(p => (
            <button key={p} onClick={() => setFilter(p)}
              className={`text-xs font-semibold px-3 py-1.5 rounded-lg border transition-colors ${filter === p ? "bg-brand-600 text-white border-brand-600" : "bg-white text-slate-600 border-slate-200 hover:bg-slate-50"}`}>
              {p}
            </button>
          ))}
        </div>
      </div>

      {/* ── Split panel ── */}
      <div className="grid grid-cols-1 lg:grid-cols-5 gap-4 items-start">

        {/* Table — 3/5 */}
        <div className="lg:col-span-3 bg-white rounded-xl border border-slate-200 overflow-hidden">
          <div className="px-5 py-3.5 border-b border-slate-100 flex items-center justify-between">
            <h2 className="font-bold text-slate-800 text-sm">Dead URL Report</h2>
            <span className="flex items-center gap-1.5 text-xs font-medium text-red-600 bg-red-50 border border-red-200 px-2 py-0.5 rounded-full">
              <AlertTriangle className="w-3 h-3" />{counts.open} open
            </span>
          </div>

          {filtered.length === 0 ? (
            <div className="py-16 text-center">
              <p className="text-sm text-slate-400">No results. <button onClick={() => { setQuery(""); setFilter("All"); }} className="text-brand-600 underline">Clear filters</button></p>
            </div>
          ) : (
            <ul className="divide-y divide-slate-100">
              {filtered.map(row => {
                const st = statuses[row.id];
                const isActive = selected?.id === row.id;
                return (
                  <li key={row.id}
                    onClick={() => setSelected(row)}
                    className={`px-4 py-3 cursor-pointer flex items-center gap-3 transition-colors ${isActive ? "bg-brand-50 border-l-2 border-brand-500" : "hover:bg-slate-50 border-l-2 border-transparent"}`}>
                    <ImpactDot score={impactScore(row)} />
                    <div className="flex-1 min-w-0">
                      <p className={`font-mono text-xs font-semibold truncate ${st === "Resolved" ? "text-slate-400 line-through" : "text-red-600"}`}>{row.deadUrl}</p>
                      <p className="text-[10px] text-slate-400 mt-0.5">
                        {row.sources.length} source{row.sources.length !== 1 ? "s" : ""} · impact {impactScore(row)} · found {row.discovered}
                      </p>
                    </div>
                    <div className="flex items-center gap-1.5 shrink-0">
                      <PriorityBadge p={row.priority} />
                      <StatusBadge s={st} />
                    </div>
                    <ChevronRight className={`w-3.5 h-3.5 shrink-0 ${isActive ? "text-brand-500" : "text-slate-300"}`} />
                  </li>
                );
              })}
            </ul>
          )}
        </div>

        {/* Detail panel — 2/5 */}
        {sel ? (
          <div className="lg:col-span-2 space-y-4">

            {/* Dead URL header */}
            <div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
              <div className="bg-slate-900 px-5 py-4">
                <p className="text-[10px] font-semibold uppercase tracking-widest text-slate-400 mb-1">Dead URL</p>
                <p className="font-mono text-sm font-bold text-red-400 break-all">{sel.deadUrl}</p>
                <div className="flex items-center gap-2 mt-2">
                  <PriorityBadge p={sel.priority} />
                  <StatusBadge s={sel.status} />
                  <span className={`text-[10px] font-semibold px-1.5 py-0.5 rounded ${fixTypeStyle[sel.fixType]}`}>{sel.fixType}</span>
                </div>
              </div>
              <div className="px-5 py-3.5">
                <p className="text-xs text-slate-500 leading-relaxed">{sel.whyItMatters}</p>
              </div>
            </div>

            {/* Source pages */}
            <div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
              <div className="px-5 py-3 border-b border-slate-100 flex items-center gap-2">
                <Link2 className="w-3.5 h-3.5 text-brand-600" />
                <h3 className="text-sm font-bold text-slate-800">Source Pages</h3>
                <span className="ml-auto text-xs text-slate-400">{sel.sources.length} link{sel.sources.length !== 1 ? "s" : ""}</span>
              </div>
              <ul className="divide-y divide-slate-100">
                {sel.sources.map((src, i) => (
                  <li key={i} className="px-5 py-3">
                    <p className="font-mono text-xs text-brand-600">{src.page}</p>
                    <p className="text-xs text-slate-500 mt-0.5">Anchor: <span className="italic">&ldquo;{src.anchorText}&rdquo;</span></p>
                  </li>
                ))}
              </ul>
            </div>

            {/* Suggested fix */}
            <div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
              <div className="px-5 py-3 border-b border-slate-100 flex items-center gap-2">
                <Wrench className="w-3.5 h-3.5 text-brand-600" />
                <h3 className="text-sm font-bold text-slate-800">Suggested Fix</h3>
              </div>
              <div className="px-5 py-4">
                <div className="flex items-start gap-2">
                  <ArrowRight className="w-4 h-4 text-green-500 mt-0.5 shrink-0" />
                  <p className="text-sm text-slate-700 font-medium">{sel.suggestedFix}</p>
                </div>
              </div>
            </div>

            {/* Resolution */}
            <div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
              <div className="px-5 py-3 border-b border-slate-100">
                <h3 className="text-sm font-bold text-slate-800">Resolution Status</h3>
              </div>
              <div className="px-5 py-4 flex items-center gap-3">
                {(["Open", "In Progress", "Resolved"] as Status[]).map(s => {
                  const active = sel.status === s;
                  const { style } = statusConfig[s];
                  return (
                    <button key={s} onClick={() => { cycleStatus(sel.id); setSelected(prev => prev ? { ...prev } : null); }}
                      className={`flex-1 py-2 text-xs font-semibold rounded-lg border transition-colors ${active ? style + " ring-2 ring-offset-1 ring-brand-400" : "bg-slate-50 text-slate-400 border-slate-200 hover:bg-slate-100"}`}>
                      {s}
                    </button>
                  );
                })}
              </div>
              <div className="px-5 pb-4">
                <button onClick={() => cycleStatus(sel.id)}
                  className="w-full py-2 text-sm font-semibold rounded-lg bg-brand-600 text-white hover:bg-brand-700 transition-colors">
                  Mark as {sel.status === "Open" ? "In Progress" : sel.status === "In Progress" ? "Resolved" : "Open"}
                </button>
              </div>
            </div>

          </div>
        ) : (
          <div className="lg:col-span-2 bg-white rounded-xl border border-slate-200 flex items-center justify-center py-24">
            <p className="text-sm text-slate-400">Select a row to view details</p>
          </div>
        )}
      </div>
    </div>
  );
}

// ─── Tab: Broken Internal Links ──────────────────────────────────────────────

function BrokenInternalLinksTab({
  links,
  loading,
  onReload,
  onPreview,
}: {
  links: BrokenInternalLink[];
  loading: boolean;
  onReload: () => void;
  onPreview: (sourcePath: string) => void;
}) {
  // Unique source pages give us the "pages affected" stat — more
  // meaningful than total link count when one page has many broken
  // links (e.g. a footer referenced from every page).
  const uniqueSources = useMemo(() => {
    const set = new Set<string>();
    for (const l of links) set.add(l.sourceUrl);
    return set.size;
  }, [links]);

  if (loading) {
    return (
      <div className="bg-white rounded-xl border border-slate-200 p-10 text-center">
        <p className="text-sm text-slate-500">Loading broken internal links…</p>
      </div>
    );
  }

  if (links.length === 0) {
    return (
      <div className="bg-white rounded-xl border border-slate-200 p-8 text-center">
        <LinkIcon className="w-10 h-10 text-slate-300 mx-auto mb-3" />
        <h2 className="text-lg font-bold text-slate-900 mb-2">No broken internal links detected</h2>
        <p className="text-sm text-slate-500 max-w-md mx-auto">
          The Site Tag hasn&apos;t reported any links pointing at dead URLs in
          the last 30 days. Install the tag on more pages or wait for visitor
          traffic to surface them — broken links are detected on every pageview.
        </p>
      </div>
    );
  }

  return (
    <div className="space-y-4">
      {/* Stat strip */}
      <div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
        <StatCard label="Broken Links" value={links.length} valueClass="text-red-600" hint="reported in last 30 days" />
        <StatCard label="Pages Affected" value={uniqueSources} valueClass="text-amber-600" hint="live pages with broken links" />
        <StatCard
          label="Broken Images"
          value={links.filter((l) => l.elementType === "img").length}
          valueClass="text-orange-600"
          hint="missing image assets"
        />
      </div>

      <div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
        <div className="px-5 py-3.5 border-b border-slate-100 flex items-center justify-between">
          <h2 className="font-bold text-slate-800 text-sm">Pages containing broken links</h2>
          <button
            onClick={onReload}
            className="inline-flex items-center gap-1.5 text-[11px] font-semibold text-slate-500 hover:text-slate-800"
          >
            <RotateCcw className="w-3 h-3" /> Refresh
          </button>
        </div>
        <div className="overflow-x-auto">
          <table className="w-full text-sm">
            <thead className="bg-slate-50 border-b border-slate-100">
              <tr className="text-left text-[11px] font-semibold uppercase tracking-wide text-slate-500">
                <th className="px-5 py-2.5">Source Page</th>
                <th className="px-5 py-2.5">Broken Link</th>
                <th className="px-5 py-2.5">Link Text</th>
                <th className="px-5 py-2.5">Section</th>
                <th className="px-5 py-2.5">Status</th>
                <th className="px-5 py-2.5 text-right">Action</th>
              </tr>
            </thead>
            <tbody className="divide-y divide-slate-100">
              {links.map((link, i) => (
                <tr key={`${link.sourceUrl}-${link.destinationUrl}-${i}`} className="hover:bg-slate-50">
                  <td className="px-5 py-3 font-mono text-xs text-brand-600 truncate max-w-[240px]" title={link.sourceUrl}>
                    {link.sourceUrl}
                  </td>
                  <td className="px-5 py-3 font-mono text-xs text-red-600 truncate max-w-[200px]" title={link.destinationUrl}>
                    {link.destinationUrl}
                  </td>
                  <td className="px-5 py-3 text-xs text-slate-600 italic truncate max-w-[180px]" title={link.linkText}>
                    &ldquo;{link.linkText || "[no text]"}&rdquo;
                  </td>
                  <td className="px-5 py-3 text-xs text-slate-500 capitalize">
                    {link.parentSection}
                    <span className="block text-[10px] text-slate-400">{link.elementType}</span>
                  </td>
                  <td className="px-5 py-3">
                    <span className="text-[10px] font-bold font-mono px-1.5 py-0.5 rounded bg-red-50 text-red-600 border border-red-200">
                      {link.statusCode}
                    </span>
                  </td>
                  <td className="px-5 py-3 text-right">
                    <button
                      onClick={() => onPreview(link.sourceUrl)}
                      className="inline-flex items-center gap-1 text-[11px] px-3 py-1.5 bg-brand-600 hover:bg-brand-700 text-white font-semibold rounded-md"
                    >
                      <Eye className="w-3 h-3" /> Preview
                    </button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

// ─── Tab: Orphan Pages ───────────────────────────────────────────────────────

function OrphanPagesTab({
  pages,
  loading,
  onReload,
}: {
  pages: OrphanPage[];
  loading: boolean;
  onReload: () => void;
}) {
  if (loading) {
    return (
      <div className="bg-white rounded-xl border border-slate-200 p-10 text-center">
        <p className="text-sm text-slate-500">Loading orphan pages…</p>
      </div>
    );
  }

  if (pages.length === 0) {
    return (
      <div className="bg-white rounded-xl border border-slate-200 p-8 text-center">
        <Ghost className="w-10 h-10 text-slate-300 mx-auto mb-3" />
        <h2 className="text-lg font-bold text-slate-900 mb-2">No orphan pages found</h2>
        <p className="text-sm text-slate-500 max-w-md mx-auto">
          Every live page has at least one internal link pointing at it.
          Orphan detection needs the Site Tag installed on enough pages to
          have a representative link graph — if the Site Tag is brand-new,
          check back in a day or two.
        </p>
      </div>
    );
  }

  const withTraffic = pages.filter((p) => p.gscClicks > 0 || p.visits > 0).length;

  return (
    <div className="space-y-4">
      <div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
        <StatCard label="Orphan Pages" value={pages.length} valueClass="text-slate-900" hint="no inbound internal links" />
        <StatCard label="With Traffic" value={withTraffic} valueClass="text-amber-600" hint="wasted GSC/visit data" />
        <StatCard label="In Nav" value={pages.filter((p) => p.isInNav).length} valueClass="text-blue-600" hint="shown in menu but not linked" />
      </div>

      <div className="bg-white rounded-xl border border-slate-200 overflow-hidden">
        <div className="px-5 py-3.5 border-b border-slate-100 flex items-center justify-between">
          <h2 className="font-bold text-slate-800 text-sm">Pages with no inbound links</h2>
          <button
            onClick={onReload}
            className="inline-flex items-center gap-1.5 text-[11px] font-semibold text-slate-500 hover:text-slate-800"
          >
            <RotateCcw className="w-3 h-3" /> Refresh
          </button>
        </div>
        <div className="overflow-x-auto">
          <table className="w-full text-sm">
            <thead className="bg-slate-50 border-b border-slate-100">
              <tr className="text-left text-[11px] font-semibold uppercase tracking-wide text-slate-500">
                <th className="px-5 py-2.5">URL</th>
                <th className="px-5 py-2.5">GSC Clicks</th>
                <th className="px-5 py-2.5">Impressions</th>
                <th className="px-5 py-2.5">In Nav</th>
                <th className="px-5 py-2.5">Recommendation</th>
              </tr>
            </thead>
            <tbody className="divide-y divide-slate-100">
              {pages.map((p) => (
                <tr key={p.url} className="hover:bg-slate-50">
                  <td className="px-5 py-3 font-mono text-xs text-brand-600 truncate max-w-[260px]" title={p.url}>
                    {p.url}
                    {p.title && <span className="block text-[10px] text-slate-400 font-sans mt-0.5 truncate">{p.title}</span>}
                  </td>
                  <td className="px-5 py-3 text-xs text-slate-700 font-semibold">{p.gscClicks.toLocaleString()}</td>
                  <td className="px-5 py-3 text-xs text-slate-500">{p.gscImpressions.toLocaleString()}</td>
                  <td className="px-5 py-3 text-xs">
                    {p.isInNav ? (
                      <span className="text-blue-600 font-semibold">Yes</span>
                    ) : (
                      <span className="text-slate-400">No</span>
                    )}
                  </td>
                  <td className="px-5 py-3 text-xs text-slate-600 max-w-md">{p.recommendation}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

// ─── Small bits ──────────────────────────────────────────────────────────────

function StatCard({
  label,
  value,
  valueClass,
  hint,
}: {
  label: string;
  value: number;
  valueClass: string;
  hint?: string;
}) {
  return (
    <div className="bg-white rounded-xl border border-slate-200 px-4 py-4">
      <p className="text-xs font-semibold text-slate-400 uppercase tracking-wide">{label}</p>
      <p className={`text-3xl font-bold mt-1 ${valueClass}`}>{value.toLocaleString()}</p>
      {hint && <p className="text-[10px] text-slate-400 mt-0.5">{hint}</p>}
    </div>
  );
}
