"use client";

/**
 * Content Audit — Page Detail Panel
 * ──────────────────────────────────
 * Expandable 2x2 grid rendered under a Content Audit row when the
 * user clicks the chevron. Four quadrants:
 *
 *   TOP-LEFT  📊 Performance   — 28d clicks / impressions / avg pos
 *                                 / CTR + 14d-vs-prior-14d trend.
 *   TOP-RIGHT 👁 Site Tag        — pageviews, landings, bounce rate,
 *                                 outbound clicks, form events,
 *                                 conversions. Renders an install CTA
 *                                 when the brand has no TrackedSite.
 *   BOTTOM-L  🎯 AI Recs         — 3-5 specific recommendations
 *                                 streamed in after the metrics
 *                                 panel renders. Each card shows
 *                                 category, title, description,
 *                                 current → suggested change, impact,
 *                                 and effort chip.
 *   BOTTOM-R  🔍 Technical      — open TechnicalIssue rows, Core
 *                                 Web Vitals (LCP/INP/CLS), dead-page
 *                                 status.
 *
 * Two fetches in parallel:
 *   GET  /api/content-audit/page-detail         — fast DB join
 *   POST /api/content-audit/page-recommendations — slower LLM call
 *                                                  (cached 24h in
 *                                                  SiteEvent)
 */

import { useEffect, useState } from "react";
import {
  BarChart3, Eye, Target, Wrench, Loader2, TrendingUp, TrendingDown,
  Minus, AlertTriangle, Sparkles, CheckCircle2, ChevronDown,
  ClipboardList, X, Tag, FileText,
} from "lucide-react";

// ─── Shared response shapes ────────────────────────────────────────────────

interface PerformanceBlock {
  clicks28d: number;
  impressions28d: number;
  avgPosition: number | null;
  ctr: number | null;
  trend: "improving" | "declining" | "stable";
  trendPct: number;
  clicksPrev14d: number;
  clicksLast14d: number;
}

interface BehaviorBlock {
  pageViews: number;
  landingSessions: number;
  bouncedSessions: number;
  bounceRate: number;
  outboundClicks: number;
  formStarts: number;
  conversions: number;
  siteTagInstalled: boolean;
}

interface TechnicalBlock {
  openIssues: Array<{ title: string; severity: string; category: string }>;
  performance: { lcpMs: number; inpMs: number; clsVal: number; performance: number } | null;
  deadPage: { priority: string; status: string } | null;
  internalLinkCount: number | null;
}

interface MetaBlock {
  title: string | null;
  description: string | null;
  source: "site_tag_snapshot" | "page_record" | "live_fetch" | "none";
}

interface Recommendation {
  title: string;
  description: string;
  currentState: string;
  suggestedChange: string;
  impact: string;
  effort: "quick_win" | "moderate" | "major";
  category: "title" | "meta" | "content" | "schema" | "internal_links" | "cta" | "speed" | "ux";
}

interface Props {
  brandId: string;
  pageUrl: string;
}

// ─── Component ─────────────────────────────────────────────────────────────

export default function PageDetailPanel({ brandId, pageUrl }: Props) {
  const [loading, setLoading] = useState(true);
  const [perf, setPerf] = useState<PerformanceBlock | null>(null);
  const [behavior, setBehavior] = useState<BehaviorBlock | null>(null);
  const [tech, setTech] = useState<TechnicalBlock | null>(null);
  const [meta, setMeta] = useState<MetaBlock | null>(null);
  const [error, setError] = useState<string | null>(null);

  const [recsLoading, setRecsLoading] = useState(false);
  const [recs, setRecs] = useState<Recommendation[] | null>(null);
  const [recsCached, setRecsCached] = useState(false);

  useEffect(() => {
    let cancelled = false;
    setLoading(true); setError(null);
    fetch(`/api/content-audit/page-detail?brandId=${brandId}&pageUrl=${encodeURIComponent(pageUrl)}`)
      .then(async (r) => {
        if (!r.ok) throw new Error((await r.json().catch(() => ({}))).error ?? "Failed to load");
        return r.json();
      })
      .then((data) => {
        if (cancelled) return;
        setPerf(data.performance);
        setBehavior(data.behavior);
        setTech(data.technical);
        setMeta(data.meta ?? null);

        // Chain the AI recs off the first fetch so the call can ship
        // the metrics the route already prepared — halves the total
        // round-trip time on a cold cache hit.
        setRecsLoading(true);
        fetch("/api/content-audit/page-recommendations", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            brandId, pageUrl,
            performance: data.performance,
            behavior: data.behavior,
            technical: data.technical,
          }),
        })
          .then((r) => (r.ok ? r.json() : null))
          .then((recsData) => {
            if (cancelled) return;
            setRecs(recsData?.recommendations ?? []);
            setRecsCached(!!recsData?.cached);
          })
          .finally(() => { if (!cancelled) setRecsLoading(false); });
      })
      .catch((err) => { if (!cancelled) setError(err instanceof Error ? err.message : "Load failed"); })
      .finally(() => { if (!cancelled) setLoading(false); });
    return () => { cancelled = true; };
  }, [brandId, pageUrl]);

  if (error) {
    return (
      <div className="bg-red-50 border border-red-200 rounded-lg p-4 text-xs text-red-700">
        Failed to load page detail: {error}
      </div>
    );
  }

  // Decide the bottom-row layout: when the technical section has real
  // content (CWV data, open issues, or a dead-page flag) we keep the
  // 2-column grid so it sits next to the recommendations. When it's
  // essentially empty, the recommendations span the full width instead
  // of leaving a "no issues" placeholder column with dead vertical
  // space below a short recommendations list.
  const techHasContent = !!tech && (
    !!tech.performance ||
    tech.openIssues.length > 0 ||
    !!tech.deadPage
  );

  return (
    <div className="bg-slate-50 border border-slate-200 rounded-lg p-5">
      {/* Meta (title + description) — rendered first because they're
          the most immediately actionable SEO levers on any page. */}
      <div className="mb-4">
        <MetaSection data={meta} loading={loading} pageUrl={pageUrl} />
      </div>
      {/* Top row — always 2 columns: Performance + Behavior. */}
      <div className="grid grid-cols-1 lg:grid-cols-2 gap-4 mb-4">
        <PerformanceSection data={perf} loading={loading} />
        <BehaviorSection data={behavior} loading={loading} />
      </div>
      {/* Bottom row — adaptive. 1 column when technical is empty so
          the recommendations get full width; 2 columns when technical
          has actual findings to show. */}
      <div className={techHasContent ? "grid grid-cols-1 lg:grid-cols-2 gap-4" : "grid grid-cols-1"}>
        <RecommendationsSection recs={recs} loading={recsLoading} cached={recsCached} />
        {techHasContent && <TechnicalSection data={tech} loading={loading} />}
      </div>
    </div>
  );
}

// ─── Meta (title + description) ────────────────────────────────────────────
//
// Thresholds below match the widely-cited Google SERP guidance:
//   Title       — ideal 50-60 chars, acceptable 30-70, bad outside.
//   Description — ideal 120-160 chars, acceptable 80-200, bad outside.
// We show the raw count + a status chip + a mock SERP preview so users
// can see what their snippet looks like before clicking through.

type MetaStatus = "ideal" | "acceptable" | "bad";

function titleStatus(len: number): MetaStatus {
  if (len >= 50 && len <= 60) return "ideal";
  if (len >= 30 && len <= 70) return "acceptable";
  return "bad";
}
function descriptionStatus(len: number): MetaStatus {
  if (len >= 120 && len <= 160) return "ideal";
  if (len >= 80 && len <= 200) return "acceptable";
  return "bad";
}

const STATUS_META: Record<MetaStatus, { label: string; chip: string; text: string }> = {
  ideal:       { label: "Ideal length",    chip: "bg-emerald-50 text-emerald-700 border-emerald-200", text: "text-emerald-700" },
  acceptable:  { label: "Acceptable",      chip: "bg-amber-50 text-amber-700 border-amber-200",       text: "text-amber-600" },
  bad:         { label: "Out of range",    chip: "bg-red-50 text-red-700 border-red-200",             text: "text-red-600" },
};

const SOURCE_LABEL: Record<MetaBlock["source"], string> = {
  site_tag_snapshot: "Site Tag snapshot",
  page_record:       "page record",
  live_fetch:        "live fetch",
  none:              "unavailable",
};

function MetaSection({ data, loading, pageUrl }: { data: MetaBlock | null; loading: boolean; pageUrl: string }) {
  return (
    <section className="bg-white rounded-lg border border-slate-200 p-4">
      <header className="flex items-center gap-2 mb-3 pb-2 border-b border-slate-100">
        <Tag className="w-3.5 h-3.5 text-indigo-600" />
        <h4 className="text-xs font-bold text-slate-800">Meta Tags</h4>
        <span className="text-[10px] text-slate-400">
          {loading ? "loading…" : data ? `source: ${SOURCE_LABEL[data.source]}` : "unavailable"}
        </span>
      </header>
      {loading ? (
        <div className="space-y-2">
          <div className="h-3 bg-slate-100 rounded animate-pulse" />
          <div className="h-3 bg-slate-100 rounded animate-pulse w-5/6" />
          <div className="h-3 bg-slate-100 rounded animate-pulse w-2/3" />
        </div>
      ) : (
        <div className="grid grid-cols-1 lg:grid-cols-2 gap-3">
          <MetaField
            kind="title"
            icon={Tag}
            label="Meta Title"
            value={data?.title ?? null}
            pageUrl={pageUrl}
          />
          <MetaField
            kind="description"
            icon={FileText}
            label="Meta Description"
            value={data?.description ?? null}
            pageUrl={pageUrl}
          />
        </div>
      )}
    </section>
  );
}

function MetaField({
  kind, icon: Icon, label, value, pageUrl,
}: {
  kind: "title" | "description";
  icon: typeof Tag;
  label: string;
  value: string | null;
  pageUrl: string;
}) {
  const len = value ? value.length : 0;
  const status = value ? (kind === "title" ? titleStatus(len) : descriptionStatus(len)) : null;
  const statusMeta = status ? STATUS_META[status] : null;
  const idealRange = kind === "title" ? "50–60" : "120–160";

  return (
    <div className="space-y-2">
      <div className="flex items-center justify-between">
        <span className="flex items-center gap-1.5 text-[11px] font-semibold text-slate-600">
          <Icon className="w-3 h-3 text-slate-400" />
          {label}
        </span>
        {value && statusMeta && (
          <span className={`text-[9px] font-bold uppercase tracking-wide px-1.5 py-0.5 rounded border ${statusMeta.chip}`}>
            {len} chars · {statusMeta.label}
          </span>
        )}
      </div>

      {value ? (
        <>
          <p className="text-[12px] text-slate-800 leading-snug bg-slate-50 rounded px-2.5 py-2 border border-slate-100">
            {value}
          </p>
          <p className="text-[10px] text-slate-400">
            Ideal: {idealRange} characters
            {status === "bad" && (
              <span className={`ml-1.5 font-semibold ${statusMeta?.text ?? ""}`}>
                {len < (kind === "title" ? 30 : 80)
                  ? "— too short, expand to land in the ideal range"
                  : "— too long, Google will truncate"}
              </span>
            )}
          </p>
          {/* SERP preview — deliberately minimal, just the blue title
              + green URL + description line that mirrors Google's
              standard result layout. */}
          <div className="rounded border border-slate-200 bg-white px-3 py-2 mt-1">
            <p className="text-[10px] text-emerald-700 font-mono truncate" title={pageUrl}>
              {pageUrl.replace(/^https?:\/\//, "").replace(/\/$/, "")}
            </p>
            {kind === "title" ? (
              <p className="text-[14px] text-blue-700 font-medium leading-tight truncate mt-0.5">
                {value}
              </p>
            ) : (
              <p className="text-[11px] text-slate-600 leading-snug mt-0.5 line-clamp-2">
                {value}
              </p>
            )}
          </div>
        </>
      ) : (
        <div className="rounded border border-red-200 bg-red-50 px-3 py-2.5">
          <p className="text-[11px] font-semibold text-red-700 flex items-center gap-1.5">
            <AlertTriangle className="w-3 h-3" />
            No {kind === "title" ? "meta title" : "meta description"} found
          </p>
          <p className="text-[10px] text-red-600 mt-1 leading-relaxed">
            {kind === "title"
              ? `Add a ${idealRange}-character title that includes the primary keyword and brand name. Titles are the single strongest on-page SEO signal and drive click-through from search results.`
              : `Add a ${idealRange}-character description summarising the page and inviting the click. Missing descriptions let Google auto-generate one from body copy, which rarely reads well.`}
          </p>
        </div>
      )}
    </div>
  );
}

// ─── Performance quadrant ──────────────────────────────────────────────────

function PerformanceSection({ data, loading }: { data: PerformanceBlock | null; loading: boolean }) {
  return (
    <Quadrant title="Performance" subtitle="28-day GSC" icon={BarChart3} iconColor="text-blue-600">
      {loading ? <Skeleton rows={4} /> : data ? (
        <>
          <Row label="Clicks"      value={data.clicks28d.toLocaleString()} />
          <Row label="Impressions" value={data.impressions28d.toLocaleString()} />
          <Row label="Avg Position" value={data.avgPosition != null ? data.avgPosition.toFixed(1) : "—"} />
          <Row label="CTR"         value={data.ctr != null ? `${data.ctr.toFixed(2)}%` : "—"} />
          <Row
            label="14d Trend"
            value={
              <span className={`inline-flex items-center gap-1 ${data.trend === "improving" ? "text-emerald-600" : data.trend === "declining" ? "text-red-500" : "text-slate-500"}`}>
                {data.trend === "improving" ? <TrendingUp className="w-3 h-3" />
                 : data.trend === "declining" ? <TrendingDown className="w-3 h-3" />
                 : <Minus className="w-3 h-3" />}
                {data.trend === "stable" ? "Stable" : `${data.trendPct > 0 ? "+" : ""}${data.trendPct}%`}
              </span>
            }
          />
        </>
      ) : <EmptyText>No GSC data for this page.</EmptyText>}
    </Quadrant>
  );
}

// ─── Behavior quadrant ─────────────────────────────────────────────────────

function BehaviorSection({ data, loading }: { data: BehaviorBlock | null; loading: boolean }) {
  return (
    <Quadrant title="Site Tag Behavior" subtitle="30-day first-party" icon={Eye} iconColor="text-violet-600">
      {loading ? <Skeleton rows={4} /> : !data || !data.siteTagInstalled ? (
        <EmptyText>
          Site Tag isn&apos;t installed for this brand — no behavioural data to show.
        </EmptyText>
      ) : (
        <>
          <Row label="Page Views"       value={data.pageViews.toLocaleString()} />
          <Row label="Landing Sessions" value={data.landingSessions.toLocaleString()} />
          <Row label="Bounce Rate"      value={data.landingSessions > 0 ? `${data.bounceRate}%` : "—"} />
          <Row label="Outbound Clicks"  value={data.outboundClicks.toLocaleString()} />
          <Row label="Form Events"      value={data.formStarts.toLocaleString()} />
          <Row label="Conversions"      value={data.conversions.toLocaleString()} valueClass={data.conversions > 0 ? "text-emerald-600 font-bold" : ""} />
        </>
      )}
    </Quadrant>
  );
}

// ─── Recommendations quadrant ──────────────────────────────────────────────

const EFFORT_META: Record<Recommendation["effort"], { label: string; class: string }> = {
  quick_win: { label: "Quick win",  class: "bg-emerald-50 text-emerald-700 border-emerald-200" },
  moderate:  { label: "Moderate",   class: "bg-amber-50 text-amber-700 border-amber-200" },
  major:     { label: "Major",      class: "bg-slate-100 text-slate-700 border-slate-200" },
};

const CATEGORY_EMOJI: Record<Recommendation["category"], string> = {
  title: "🏷️", meta: "📝", content: "📄", schema: "🔖",
  internal_links: "🔗", cta: "📣", speed: "⚡", ux: "✨",
};

/** Logical grouping for the accordion section headers. The eight
 *  backend categories collapse down to four user-facing groups so
 *  users scan a short, stable list ("On-Page / Content / Technical /
 *  Conversion") instead of reading eight tiny subheaders. Order in
 *  this Record also determines render order of the groups. */
const CATEGORY_GROUP: Record<Recommendation["category"], "On-Page" | "Content" | "Technical" | "Conversion"> = {
  title: "On-Page",
  meta: "On-Page",
  content: "Content",
  schema: "Technical",
  internal_links: "Technical",
  speed: "Technical",
  cta: "Conversion",
  ux: "Conversion",
};

const GROUP_ORDER: Array<"On-Page" | "Content" | "Technical" | "Conversion"> = [
  "On-Page", "Content", "Technical", "Conversion",
];

function RecommendationsSection({ recs, loading, cached }: { recs: Recommendation[] | null; loading: boolean; cached: boolean }) {
  // Accordion state: set of recommendation indices currently expanded.
  // Previously a single `number | null` which enforced one-at-a-time by
  // construction — now a Set so "Expand All" can legitimately open
  // every tile at once. Individual tile clicks still behave as an
  // accordion (opening one auto-closes the others, per the spec);
  // only the top-level Expand All button opens them in parallel.
  const [expandedIds, setExpandedIds] = useState<Set<number>>(new Set());
  // Local dismissal — hides a rec for the rest of this page-detail
  // session. No persistence yet; a full dismissal would need a new
  // SiteEvent row, which is out of scope for the UI-only tweak.
  const [dismissed, setDismissed] = useState<Set<number>>(new Set());

  function toggle(i: number) {
    setExpandedIds((prev) => {
      const next = new Set<number>();
      // Accordion semantics: clicking an open tile closes it
      // (leaving the set empty); clicking a closed tile closes
      // any other tile and opens just this one.
      if (!prev.has(i)) next.add(i);
      return next;
    });
  }
  function dismiss(i: number) {
    setDismissed((prev) => new Set(prev).add(i));
    setExpandedIds((prev) => {
      const next = new Set(prev);
      next.delete(i);
      return next;
    });
  }

  const visibleRecs = (recs ?? []).slice(0, 5)
    .map((r, i) => ({ rec: r, origIdx: i }))
    .filter(({ origIdx }) => !dismissed.has(origIdx));

  // Group recs for section headers. Keeps the original indices so
  // dismiss + expand toggles still reference the right rec regardless
  // of visual grouping. Groups without any recs drop out entirely.
  const grouped = GROUP_ORDER
    .map((group) => ({
      group,
      items: visibleRecs.filter(({ rec }) => CATEGORY_GROUP[rec.category] === group),
    }))
    .filter(({ items }) => items.length > 0);

  const allExpanded = visibleRecs.length > 0 && expandedIds.size === visibleRecs.length;
  function expandAll() {
    setExpandedIds(new Set(visibleRecs.map(({ origIdx }) => origIdx)));
  }
  function collapseAll() {
    setExpandedIds(new Set());
  }

  return (
    <Quadrant
      title="AI Recommendations"
      subtitle={cached ? "cached · 24h" : loading ? "generating…" : "live"}
      icon={Target}
      iconColor="text-emerald-600"
    >
      {loading && !recs ? (
        <div className="flex items-center gap-2 text-xs text-slate-500 py-3">
          <Loader2 className="w-3.5 h-3.5 animate-spin" />
          Generating AI recommendations…
        </div>
      ) : visibleRecs.length > 0 ? (
        <div className="space-y-3">
          {/* Top-level expand/collapse control. Only rendered when
              there are 2+ recs — with a single rec it's just visual
              noise (the tile itself is the only thing to toggle). */}
          {visibleRecs.length > 1 && (
            <div className="flex items-center justify-end -mt-1">
              <button
                type="button"
                onClick={allExpanded ? collapseAll : expandAll}
                className="text-[10px] font-semibold text-slate-500 hover:text-slate-700 underline underline-offset-2"
              >
                {allExpanded ? "Collapse all" : "Expand all"}
              </button>
            </div>
          )}
          {grouped.map(({ group, items }) => (
            <div key={group} className="space-y-1.5">
              {/* Group header — small uppercase label. Hidden when
                  there's only one group in view so a page with all
                  recs in (say) "Content" doesn't get a redundant
                  subheader above the list. */}
              {grouped.length > 1 && (
                <p className="text-[9px] font-bold uppercase tracking-widest text-slate-400 px-1">
                  {group}
                </p>
              )}
              <ul className="space-y-1.5">
                {items.map(({ rec: r, origIdx: i }) => {
                  const effort = EFFORT_META[r.effort];
                  const isOpen = expandedIds.has(i);
                  return (
                    <li key={i}>
                      {/* Collapsed tile — single 44px row. Click anywhere on
                          the tile body toggles expansion. */}
                      <button
                        type="button"
                        onClick={() => toggle(i)}
                        aria-expanded={isOpen}
                        className={`w-full flex items-center justify-between gap-2 px-3 py-2.5 bg-white border border-slate-200 hover:bg-slate-50 transition-colors ${isOpen ? "rounded-t-lg border-b-0" : "rounded-lg"}`}
                      >
                        <span className="flex items-center gap-2 min-w-0 flex-1 text-left">
                          <span className="text-sm shrink-0" aria-hidden>{CATEGORY_EMOJI[r.category]}</span>
                          <span className="text-xs font-semibold text-slate-900 truncate">{r.title}</span>
                        </span>
                        <span className="flex items-center gap-2 shrink-0">
                          <span className={`text-[9px] font-bold uppercase tracking-wide px-1.5 py-0.5 rounded border ${effort.class}`}>
                            {effort.label}
                          </span>
                          <ChevronDown className={`w-3.5 h-3.5 text-slate-400 transition-transform ${isOpen ? "rotate-180" : ""}`} />
                        </span>
                      </button>

                      {/* Expanded body — uses max-height transition for a
                          200ms slide-open rather than a hard unmount/mount.
                          The inner overflow-hidden + large-but-bounded
                          max-h-[500px] is enough for any rec body we
                          generate (tiles cap at ~200px of content) while
                          still animating smoothly. Rendering it always —
                          just height-0 when collapsed — avoids a jarring
                          content-pop on open. */}
                      <div
                        className={`overflow-hidden transition-[max-height] duration-200 ease-out ${isOpen ? "max-h-[500px]" : "max-h-0"}`}
                        aria-hidden={!isOpen}
                      >
                        <div className="px-3 py-3 bg-slate-50 border border-t-0 border-slate-200 rounded-b-lg space-y-2.5">
                          <p className="text-[11px] text-slate-600 leading-relaxed">{r.description}</p>
                          {(r.currentState || r.suggestedChange) && (
                            <div className="grid grid-cols-2 gap-2">
                              {r.currentState && (
                                <div className="bg-white border border-slate-200 rounded p-2">
                                  <p className="text-[9px] font-bold uppercase tracking-widest text-slate-400 mb-0.5">Current</p>
                                  <p className="text-[11px] text-slate-600">{r.currentState}</p>
                                </div>
                              )}
                              {r.suggestedChange && (
                                <div className="bg-emerald-50 border border-emerald-200 rounded p-2">
                                  <p className="text-[9px] font-bold uppercase tracking-widest text-emerald-600 mb-0.5">Suggest</p>
                                  <p className="text-[11px] text-emerald-800">{r.suggestedChange}</p>
                                </div>
                              )}
                            </div>
                          )}
                          {r.impact && (
                            <p className="text-[10px] font-semibold text-blue-600 inline-flex items-center gap-1">
                              <Sparkles className="w-2.5 h-2.5" /> Expected impact: {r.impact}
                            </p>
                          )}
                          <div className="flex gap-2 pt-1">
                            {/* Task creation is deliberately client-only for
                                now — no backend integration yet. The spec
                                leaves the task API TBD so this button is
                                visually live but a no-op placeholder. */}
                            <button
                              type="button"
                              className="inline-flex items-center gap-1 text-[10px] font-semibold px-2.5 py-1 bg-slate-700 hover:bg-slate-800 text-white rounded"
                            >
                              <ClipboardList className="w-3 h-3" /> Create Task
                            </button>
                            <button
                              type="button"
                              onClick={() => dismiss(i)}
                              className="inline-flex items-center gap-1 text-[10px] font-semibold px-2.5 py-1 bg-slate-200 hover:bg-slate-300 text-slate-600 rounded"
                            >
                              <X className="w-3 h-3" /> Dismiss
                            </button>
                          </div>
                        </div>
                      </div>
                    </li>
                  );
                })}
              </ul>
            </div>
          ))}
        </div>
      ) : (
        <EmptyText>
          No recommendations yet. This usually means the page is healthy — or
          the AI didn&apos;t find anything actionable given the available data.
        </EmptyText>
      )}
    </Quadrant>
  );
}

// ─── Technical quadrant ────────────────────────────────────────────────────

const SEVERITY_COLORS: Record<string, string> = {
  critical: "text-red-700 bg-red-50 border-red-200",
  high:     "text-orange-700 bg-orange-50 border-orange-200",
  medium:   "text-amber-700 bg-amber-50 border-amber-200",
  low:      "text-slate-600 bg-slate-50 border-slate-200",
};

function TechnicalSection({ data, loading }: { data: TechnicalBlock | null; loading: boolean }) {
  return (
    <Quadrant title="Technical" subtitle="latest audit" icon={Wrench} iconColor="text-orange-600">
      {loading ? <Skeleton rows={4} /> : data ? (
        <>
          {data.deadPage && (
            <div className="bg-red-50 border border-red-200 rounded p-2 mb-2 flex items-start gap-1.5">
              <AlertTriangle className="w-3 h-3 text-red-500 mt-0.5 shrink-0" />
              <span className="text-[11px] text-red-700 font-semibold">
                Flagged as dead page ({data.deadPage.priority} priority)
              </span>
            </div>
          )}
          {data.performance ? (
            <>
              <Row label="LCP" value={`${(data.performance.lcpMs / 1000).toFixed(1)}s`} valueClass={data.performance.lcpMs > 2500 ? "text-red-600" : "text-emerald-600"} />
              <Row label="INP" value={`${data.performance.inpMs}ms`} valueClass={data.performance.inpMs > 200 ? "text-red-600" : "text-emerald-600"} />
              <Row label="CLS" value={data.performance.clsVal.toFixed(3)} valueClass={data.performance.clsVal > 0.1 ? "text-red-600" : "text-emerald-600"} />
              <Row label="Perf Score" value={`${data.performance.performance}/100`} />
            </>
          ) : (
            <p className="text-[11px] text-slate-400 italic mb-2">No Core Web Vitals data for this page.</p>
          )}
          <div className="mt-2">
            <p className="text-[10px] font-bold uppercase tracking-widest text-slate-400 mb-1">
              Open Issues ({data.openIssues.length})
            </p>
            {data.openIssues.length === 0 ? (
              <p className="text-[11px] text-emerald-600 inline-flex items-center gap-1">
                <CheckCircle2 className="w-3 h-3" /> No open issues for this page.
              </p>
            ) : (
              <ul className="space-y-1">
                {data.openIssues.slice(0, 6).map((issue, i) => (
                  <li key={i} className="flex items-start gap-1.5">
                    <span className={`text-[9px] font-bold uppercase tracking-wide px-1.5 py-0.5 rounded border ${SEVERITY_COLORS[issue.severity] || SEVERITY_COLORS.low} shrink-0`}>
                      {issue.severity}
                    </span>
                    <span className="text-[11px] text-slate-700 flex-1">{issue.title}</span>
                  </li>
                ))}
                {data.openIssues.length > 6 && (
                  <li className="text-[10px] text-slate-400 italic">…and {data.openIssues.length - 6} more</li>
                )}
              </ul>
            )}
          </div>
        </>
      ) : <EmptyText>No technical data available.</EmptyText>}
    </Quadrant>
  );
}

// ─── Shared primitives ─────────────────────────────────────────────────────

function Quadrant({
  title, subtitle, icon: Icon, iconColor, children,
}: {
  title: string; subtitle: string; icon: typeof BarChart3;
  iconColor: string; children: React.ReactNode;
}) {
  return (
    <section className="bg-white rounded-lg border border-slate-200 p-4">
      <header className="flex items-center gap-2 mb-3 pb-2 border-b border-slate-100">
        <Icon className={`w-3.5 h-3.5 ${iconColor}`} />
        <h4 className="text-xs font-bold text-slate-800">{title}</h4>
        <span className="text-[10px] text-slate-400">{subtitle}</span>
      </header>
      {children}
    </section>
  );
}

function Row({
  label, value, valueClass,
}: { label: string; value: React.ReactNode; valueClass?: string }) {
  return (
    <div className="flex items-center justify-between py-1">
      <span className="text-[11px] text-slate-500">{label}</span>
      <span className={`text-xs tabular-nums ${valueClass ?? "text-slate-800 font-semibold"}`}>{value}</span>
    </div>
  );
}

function Skeleton({ rows }: { rows: number }) {
  return (
    <div className="space-y-2">
      {Array.from({ length: rows }).map((_, i) => (
        <div key={i} className="h-3 bg-slate-100 rounded animate-pulse" />
      ))}
    </div>
  );
}

function EmptyText({ children }: { children: React.ReactNode }) {
  return <p className="text-xs text-slate-400 italic">{children}</p>;
}
