"use client";

import { useState, useEffect, useCallback } from "react";
import { MousePointer, BarChart3, Eye, Clock, ChevronDown, CheckCircle2, AlertCircle, XCircle } from "lucide-react";
import { CardShell, TableSkeleton } from "./_shared";

interface HeatmapData {
  pages: string[];
  clicks: Array<{
    element: string;
    count: number;
    page: string;
    /** Percentage of clicks on this element that landed above the
     *  fold. Used by the Click Heatmap pill instead of the old
     *  rank-based heuristic (which mislabelled half the rows). */
    aboveFoldPct?: number;
    avgPositionX?: number | null;
    avgPositionY?: number | null;
  }>;
  scrollDepth: Array<{ milestone: number; count: number; pct: number }>;
  scrollSamples: number;
  attention: Array<{ selector: string; label: string | null; avgTime: number; samples: number }>;
  ctaVisibility: Array<{ page: string; elementType: string; elementTag?: string; text: string; label?: string; seen: number; avgTimeToSee: number }>;
}

export interface HeatmapsTabProps {
  brandId: string;
  range: string;
}

/** Interpolate red → orange → yellow → green based on rank.
 * 0 = most clicked (red), 1 = least clicked (cool blue). */
function heatColor(rank01: number): string {
  if (rank01 < 0.15) return "bg-red-500";
  if (rank01 < 0.3) return "bg-orange-500";
  if (rank01 < 0.5) return "bg-amber-500";
  if (rank01 < 0.7) return "bg-yellow-500";
  if (rank01 < 0.85) return "bg-lime-500";
  return "bg-emerald-500";
}

/** Scroll depth bar gradient: green at 100%, red at 25% */
function scrollColor(milestone: number): string {
  if (milestone >= 90) return "bg-emerald-500";
  if (milestone >= 75) return "bg-lime-500";
  if (milestone >= 50) return "bg-amber-500";
  if (milestone >= 25) return "bg-orange-500";
  return "bg-red-500";
}

/** Attention time color: longer = warmer */
function attentionColor(seconds: number, max: number): string {
  const r = max > 0 ? seconds / max : 0;
  if (r > 0.75) return "bg-red-500";
  if (r > 0.5) return "bg-orange-500";
  if (r > 0.25) return "bg-amber-500";
  return "bg-slate-400";
}

export function HeatmapsTab({ brandId, range }: HeatmapsTabProps) {
  const [data, setData] = useState<HeatmapData | null>(null);
  const [loading, setLoading] = useState(true);
  const [page, setPage] = useState("");
  const [pageDropdown, setPageDropdown] = useState(false);

  const load = useCallback(async () => {
    setLoading(true);
    const params = new URLSearchParams({ brandId, range });
    if (page) params.set("page", page);
    const res = await fetch(`/api/site-tag/analytics/heatmap?${params}`);
    if (res.ok) setData(await res.json());
    setLoading(false);
  }, [brandId, range, page]);

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

  if (loading) {
    return (
      <div className="space-y-6">
        <TableSkeleton rows={6} cols={3} />
        <TableSkeleton rows={5} cols={2} />
      </div>
    );
  }

  const empty = !data || (data.clicks.length === 0 && data.scrollSamples === 0 && data.attention.length === 0 && data.ctaVisibility.length === 0);
  if (empty) {
    return (
      <div className="bg-white rounded-xl border border-slate-200 p-12 text-center">
        <MousePointer className="w-10 h-10 text-slate-200 mx-auto mb-3" />
        <h2 className="text-lg font-bold text-slate-900 mb-1">No Heatmap Data Yet</h2>
        <p className="text-sm text-slate-500 max-w-sm mx-auto">
          This data will appear once the Site Tag is installed and collecting click, scroll, and attention events.
        </p>
      </div>
    );
  }

  const maxClicks = data!.clicks[0]?.count ?? 1;
  const maxAttention = data!.attention[0]?.avgTime ?? 1;

  return (
    <div className="space-y-6">
      {/* Page selector */}
      {data!.pages.length > 0 && (
        <div className="flex items-center gap-2">
          <span className="text-xs font-semibold text-slate-500 uppercase tracking-wide">Page Filter</span>
          <div className="relative">
            <button onClick={() => setPageDropdown(!pageDropdown)} className="flex items-center gap-2 px-3 py-2 border border-slate-200 rounded-lg text-xs font-medium text-slate-600 hover:bg-slate-50 min-w-[240px]">
              <span className="truncate flex-1 text-left">{page || "All Pages"}</span>
              <ChevronDown className="w-3 h-3 text-slate-400" />
            </button>
            {pageDropdown && (
              <>
                <div className="fixed inset-0 z-30" onClick={() => setPageDropdown(false)} />
                <div className="absolute top-full left-0 mt-1 bg-white border border-slate-200 rounded-lg shadow-lg z-40 py-1 w-64 max-h-60 overflow-y-auto">
                  <button onClick={() => { setPage(""); setPageDropdown(false); }} className={`w-full text-left px-3 py-2 text-xs hover:bg-slate-50 ${!page ? "text-brand-600 font-semibold" : "text-slate-600"}`}>All Pages</button>
                  {data!.pages.map((p) => (
                    <button key={p} onClick={() => { setPage(p); setPageDropdown(false); }} className={`w-full text-left px-3 py-2 text-xs font-mono hover:bg-slate-50 truncate ${page === p ? "text-brand-600 font-semibold" : "text-slate-600"}`}>{p}</button>
                  ))}
                </div>
              </>
            )}
          </div>
        </div>
      )}

      {/* Click Heatmap — ranked list with heat-colored bars */}
      {data!.clicks.length > 0 && (
        <CardShell
          title="Click Heatmap"
          icon={MousePointer}
          right={<span className="text-[10px] font-semibold text-slate-400 uppercase tracking-widest">Top {Math.min(data!.clicks.length, 20)}</span>}
        >
          <div className="divide-y divide-slate-100">
            {data!.clicks.slice(0, 20).map((c, i) => {
              const pct = (c.count / maxClicks) * 100;
              const rank01 = i / Math.max(data!.clicks.length - 1, 1);
              const color = heatColor(rank01);
              // Above-fold status is now DATA-driven — heatmap.js
              // measures the click target's getBoundingClientRect
              // vs window.innerHeight at click time, aggregated as
              // aboveFoldPct per element. Majority-above-fold (>=50%)
              // is treated as "above fold" for the pill. Falls back
              // to the legacy rank heuristic for rows from events
              // written before this commit.
              const pctAbove = typeof c.aboveFoldPct === "number" ? c.aboveFoldPct : (i < 5 ? 100 : 0);
              const isAboveFold = pctAbove >= 50;
              // element falls back to a page-path-prefixed description
              // for the rare "unknown" bucket so the operator still
              // sees WHERE on the site those clicks happened.
              const elementLabel = c.element === "unknown"
                ? `unknown element on ${c.page.replace(/^https?:\/\/[^/]+/, "") || "/"}`
                : c.element;
              return (
                <div key={i} className="px-5 py-3 flex items-center gap-4 hover:bg-slate-50 transition-colors">
                  <span className="text-[11px] font-bold text-slate-400 tabular-nums w-6">#{i + 1}</span>
                  <div className="flex-1 min-w-0">
                    <div className="flex items-center justify-between mb-1 gap-3">
                      <div className="min-w-0 flex-1">
                        <span className="font-semibold text-xs text-slate-800 truncate block" title={c.element}>{elementLabel}</span>
                        <span className="text-[10px] text-slate-400 font-mono truncate block" title={c.page}>
                          {c.page.replace(/^https?:\/\/[^/]+/, "") || "/"}
                        </span>
                      </div>
                      <span className="text-xs font-bold text-slate-900 tabular-nums shrink-0 ml-2">{c.count.toLocaleString()} clicks</span>
                    </div>
                    <div className="w-full bg-slate-100 rounded-full h-2 overflow-hidden">
                      <div className={`h-full rounded-full transition-all ${color}`} style={{ width: `${Math.max(pct, 2)}%` }} />
                    </div>
                  </div>
                  <span
                    className={`text-[9px] font-semibold px-1.5 py-0.5 rounded shrink-0 ${isAboveFold ? "bg-emerald-50 text-emerald-700 border border-emerald-200" : "bg-slate-100 text-slate-500 border border-slate-200"}`}
                    title={typeof c.aboveFoldPct === "number" ? `${c.aboveFoldPct}% of clicks above fold` : undefined}
                  >
                    {isAboveFold ? "above fold" : "below fold"}
                    {typeof c.aboveFoldPct === "number" && c.aboveFoldPct > 0 && c.aboveFoldPct < 100 && (
                      <span className="ml-1 opacity-60">{c.aboveFoldPct}%</span>
                    )}
                  </span>
                </div>
              );
            })}
          </div>
        </CardShell>
      )}

      {/* Scroll Depth — full-width, gradient colors */}
      {data!.scrollSamples > 0 && (
        <CardShell
          title="Scroll Depth"
          icon={BarChart3}
          right={<span className="text-[10px] font-semibold text-slate-400 uppercase tracking-widest">{data!.scrollSamples.toLocaleString()} samples</span>}
        >
          <div className="px-5 py-5 space-y-3">
            {data!.scrollDepth.map((s) => (
              <div key={s.milestone}>
                <div className="flex items-center justify-between mb-1.5">
                  <span className="text-sm font-semibold text-slate-700 tabular-nums">{s.milestone}% scrolled</span>
                  <span className="text-xs text-slate-500 tabular-nums">{s.count.toLocaleString()} ({s.pct}%)</span>
                </div>
                <div className="w-full bg-slate-100 rounded-full h-5 overflow-hidden">
                  <div
                    className={`h-full rounded-full flex items-center justify-end pr-2 transition-all ${scrollColor(s.milestone)}`}
                    style={{ width: `${Math.max(s.pct, 3)}%` }}
                  >
                    {s.pct >= 10 && <span className="text-[10px] font-bold text-white">{s.pct}%</span>}
                  </div>
                </div>
              </div>
            ))}
          </div>
        </CardShell>
      )}

      {/* Section Attention — horizontal bars, warm/cool colors.
          The `samples` count represents pageviews-that-included-this-section,
          not unique visitors. The API at /api/site-tag/analytics/heatmap
          does NOT deduplicate by sessionId/visitorId — each HeatmapEvent row
          is one attention beacon from one pageview, so samples equals the
          number of pageview beacons that reported time in this section. */}
      {data!.attention.length > 0 && (
        <CardShell
          title="Section Attention"
          icon={Clock}
          right={<span className="text-[10px] font-semibold text-slate-400 uppercase tracking-widest">Avg time per pageview</span>}
        >
          <div className="divide-y divide-slate-100">
            {data!.attention.map((a, i) => {
              const width = maxAttention > 0 ? (a.avgTime / maxAttention) * 100 : 0;
              const color = attentionColor(a.avgTime, maxAttention);
              // Truncate long headings so the card row never blows out
              const rawLabel = a.label || a.selector;
              const truncated = rawLabel.length > 60 ? rawLabel.slice(0, 59) + "\u2026" : rawLabel;
              // Tooltip shows the full label + selector if both exist
              const tooltip = a.label
                ? (rawLabel.length > 60 ? `${rawLabel}\n${a.selector}` : a.selector)
                : undefined;
              return (
                <div key={i} className="px-5 py-3 hover:bg-slate-50 transition-colors">
                  <div className="flex items-center justify-between mb-1.5">
                    <span
                      className={`text-xs truncate max-w-[500px] ${a.label ? "font-semibold text-slate-800" : "font-mono text-slate-600"}`}
                      title={tooltip}
                    >
                      {truncated}
                    </span>
                    <span className="text-xs text-slate-400 shrink-0 tabular-nums">
                      {a.samples} {a.samples === 1 ? "pageview" : "pageviews"}
                    </span>
                  </div>
                  <div className="flex items-center gap-3">
                    <div className="flex-1 bg-slate-100 rounded-full h-2 overflow-hidden">
                      <div className={`h-full rounded-full ${color} transition-all`} style={{ width: `${Math.max(width, 2)}%` }} />
                    </div>
                    <span className="text-sm font-bold text-slate-900 tabular-nums w-20 text-right">
                      avg {a.avgTime}s
                    </span>
                  </div>
                </div>
              );
            })}
          </div>
        </CardShell>
      )}

      {/* CTA Visibility — status icons per row */}
      {data!.ctaVisibility.length > 0 && (
        <CardShell title="CTA Visibility" icon={Eye}>
          {/* Legend. Visibility here is relative to the MOST-seen CTA in
              the window (seen / topSeen * 100) — not a true % of sessions,
              since we don't have per-session denominators at the route
              level. The thresholds align with the labels below. */}
          <div className="px-5 py-3 border-b border-slate-100 bg-slate-50/60 text-[11px] flex flex-wrap gap-x-5 gap-y-1.5 text-slate-600">
            <span className="inline-flex items-center gap-1.5"><CheckCircle2 className="w-3.5 h-3.5 text-emerald-500" /><strong className="text-slate-800">80-100%</strong> Seen by most visitors — good placement</span>
            <span className="inline-flex items-center gap-1.5"><AlertCircle className="w-3.5 h-3.5 text-amber-500" /><strong className="text-slate-800">40-79%</strong> Seen by some — consider moving higher on the page</span>
            <span className="inline-flex items-center gap-1.5"><XCircle className="w-3.5 h-3.5 text-red-500" /><strong className="text-slate-800">0-39%</strong> Missed by most — needs to be above the fold</span>
          </div>
          <table className="w-full text-sm">
            <thead>
              <tr className="text-left text-[11px] font-semibold uppercase tracking-wider text-slate-400 border-b border-slate-100">
                <th className="px-5 py-2.5 w-10"></th>
                <th className="px-5 py-2.5">Page</th>
                <th className="px-5 py-2.5">Element</th>
                <th className="px-5 py-2.5 text-right">Visibility</th>
                <th className="px-5 py-2.5 text-right">Avg Time to See</th>
              </tr>
            </thead>
            <tbody className="divide-y divide-slate-100">
              {data!.ctaVisibility.map((c, i) => {
                // Relative visibility: highest-seen CTA in the window is
                // the 100% benchmark. Not a per-session %, but a
                // reasonable proxy when all you have is observation counts.
                const visibility = data!.ctaVisibility.length > 0
                  ? (c.seen / data!.ctaVisibility[0].seen) * 100
                  : 0;
                const status = visibility >= 80
                  ? { Icon: CheckCircle2, color: "text-emerald-500", bg: "bg-emerald-500", label: "Good" }
                  : visibility >= 40
                  ? { Icon: AlertCircle, color: "text-amber-500", bg: "bg-amber-500", label: "Fair" }
                  : { Icon: XCircle, color: "text-red-500", bg: "bg-red-500", label: "Poor" };
                const StatusIcon = status.Icon;
                const elementLabel = formatCtaLabel(c);
                const tooltip =
                  status.label === "Good"
                    ? `${Math.round(visibility)}% visibility — this CTA is seen by most visitors who land on the page.`
                    : status.label === "Fair"
                    ? `${Math.round(visibility)}% visibility — about half of visitors scroll past without seeing it. Consider moving higher on the page.`
                    : `${Math.round(visibility)}% visibility — most visitors never see this CTA. Move it above the fold or add a secondary placement.`;
                return (
                  <tr key={i} className="hover:bg-slate-50 transition-colors" title={tooltip}>
                    <td className="px-5 py-3">
                      <StatusIcon className={`w-4 h-4 ${status.color}`} aria-label={status.label} />
                    </td>
                    <td className="px-5 py-3 font-mono text-xs text-brand-600 truncate max-w-[200px]">{c.page}</td>
                    <td className="px-5 py-3 text-xs text-slate-700 truncate max-w-[280px]" title={elementLabel}>
                      {elementLabel}
                    </td>
                    <td className="px-5 py-3 text-right">
                      <div className="flex items-center gap-2 justify-end">
                        <div className="w-16 bg-slate-100 rounded-full h-1.5 overflow-hidden">
                          <div
                            className={`h-full rounded-full ${status.bg}`}
                            style={{ width: `${Math.min(100, Math.max(visibility, 3))}%` }}
                          />
                        </div>
                        <span className="text-xs font-bold text-slate-900 tabular-nums w-10">{Math.round(visibility)}%</span>
                      </div>
                    </td>
                    <td className="px-5 py-3 text-right text-slate-500 tabular-nums">
                      {formatTimeToSee(c.avgTimeToSee)}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </CardShell>
      )}
    </div>
  );
}

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

/**
 * Build the "Element" column label. Prefixes the HTML tag type (Button /
 * Link / Form / Input) so the user can tell a phone number link from a
 * form submit at a glance, falls back to a friendly type when the tag
 * wasn't captured (legacy events), and formats tel: phone numbers as
 * "Phone: (xxx) xxx-xxxx" to match the Conversion Breakdown vocabulary.
 */
function formatCtaLabel(c: {
  elementType: string;
  elementTag?: string;
  text: string;
  label?: string;
}): string {
  // Prefer the accessible label (aria-label / title) when the raw text is
  // empty or just an icon character.
  const raw = (c.text && c.text.trim().length > 1) ? c.text.trim() : (c.label ?? "").trim();

  // Map element type → readable prefix. elementType is "phone"|"email"|
  // "form"|"cta" from the collector; fall back to the tag when ambiguous.
  const tag = (c.elementTag ?? "").toLowerCase();
  let prefix: string;
  if (c.elementType === "phone") prefix = "Phone";
  else if (c.elementType === "email") prefix = "Email";
  else if (c.elementType === "form") prefix = "Form";
  else if (tag === "button") prefix = "Button";
  else if (tag === "a") prefix = "Link";
  else if (tag === "form") prefix = "Form";
  else if (tag === "input") prefix = "Input";
  else prefix = "CTA";

  if (!raw) return prefix;
  return `${prefix}: ${raw}`;
}

/** Format "Avg Time to See" seconds. Anything over 60s reads more naturally
 *  as "1m 23s" than as "83s"; under 60s stays in seconds with one decimal. */
function formatTimeToSee(seconds: number): string {
  if (!seconds || seconds <= 0) return "—";
  if (seconds < 60) return `${seconds}s`;
  const mins = Math.floor(seconds / 60);
  const rem = Math.round(seconds - mins * 60);
  return rem === 0 ? `${mins}m` : `${mins}m ${rem}s`;
}
