import { useCallback, useEffect, useRef, useState } from "react";
import { SidebarNav } from "./CreatorDashboard";
import { useAuth } from "../context/AuthContext";
import { ApiError } from "../api/client";
import {
  fetchCreatorHighlights,
  fetchHighlightDetail,
  updateHighlightStatus,
  trimHighlight,
  type HighlightCandidate,
  type ScoreBreakdown,
} from "../api/highlights";
import {
  generateShorts,
  fetchShorts,
  getShortDownloadUrl,
  type GeneratedShort,
} from "../api/shorts";
import {
  fetchShortsTemplate,
  updateShortsTemplate,
  type ShortsTemplateConfig,
} from "../api/templates";
import { useDocumentTitle } from "../hooks/useDocumentTitle";
import styles from "./HighlightQueue.module.css";

/* ── Helpers ────────────────────────────────────────────────────────────────── */

async function copyToClipboard(text: string): Promise<boolean> {
  if (navigator.clipboard) {
    try {
      await navigator.clipboard.writeText(text);
      return true;
    } catch { /* fall through */ }
  }
  const ta = document.createElement("textarea");
  ta.value = text;
  ta.style.position = "fixed";
  ta.style.left = "-9999px";
  document.body.appendChild(ta);
  ta.select();
  const ok = document.execCommand("copy");
  document.body.removeChild(ta);
  return ok;
}

function formatDuration(secs: number): string {
  const m = Math.floor(secs / 60);
  const s = Math.floor(secs % 60);
  return `${m}:${s.toString().padStart(2, "0")}`;
}

function statusBadgeClass(status: string): string {
  switch (status) {
    case "approved":
      return styles.badgeApproved ?? "";
    case "rejected":
      return styles.badgeRejected ?? "";
    default:
      return styles.badgeCandidate ?? "";
  }
}

function shortStatusClass(status: string): string {
  switch (status) {
    case "complete":
      return styles.shortStatusComplete ?? "";
    case "failed":
      return styles.shortStatusFailed ?? "";
    case "processing":
      return styles.shortStatusProcessing ?? "";
    default:
      return styles.shortStatusPending ?? "";
  }
}

function formatPresetLabel(preset: string): string {
  switch (preset) {
    case "vertical":
      return "9:16";
    case "square":
      return "1:1";
    case "horizontal":
      return "16:9";
    default:
      return preset;
  }
}

function canGenerateShorts(shorts: GeneratedShort[]): boolean {
  if (shorts.length === 0) return true;
  // Can re-generate if all existing shorts failed
  return shorts.every((s) => s.status === "failed");
}

function hasProcessingShorts(shorts: GeneratedShort[]): boolean {
  return shorts.some(
    (s) => s.status === "pending" || s.status === "processing",
  );
}

const BREAKDOWN_LABELS: { key: keyof ScoreBreakdown; label: string }[] = [
  { key: "duration_score", label: "Duration" },
  { key: "content_density_score", label: "Content Density" },
  { key: "technique_relevance_score", label: "Technique" },
  { key: "position_score", label: "Position" },
  { key: "uniqueness_score", label: "Uniqueness" },
  { key: "engagement_proxy_score", label: "Engagement" },
  { key: "plugin_diversity_score", label: "Plugin Diversity" },
];

type FilterTab = "all" | "shorts" | "approved" | "rejected";

const POLL_INTERVAL_MS = 5000;

/* ── Component ──────────────────────────────────────────────────────────────── */

export default function HighlightQueue() {
  useDocumentTitle("Highlight Queue");

  const [highlights, setHighlights] = useState<HighlightCandidate[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [activeTab, setActiveTab] = useState<FilterTab>("all");
  const [expandedId, setExpandedId] = useState<string | null>(null);
  const [trimStart, setTrimStart] = useState<string>("");
  const [trimEnd, setTrimEnd] = useState<string>("");
  const [actionLoading, setActionLoading] = useState<string | null>(null);

  // Shorts state: highlight_id → GeneratedShort[]
  const [shortsMap, setShortsMap] = useState<Map<string, GeneratedShort[]>>(
    new Map(),
  );
  const [generatingIds, setGeneratingIds] = useState<Set<string>>(new Set());
  const [copiedShort, setCopiedShort] = useState<{ id: string; kind: "share" | "embed" } | null>(null);
  const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);

  // Template config state
  const { user } = useAuth();
  const [templateOpen, setTemplateOpen] = useState(false);
  const [template, setTemplate] = useState<ShortsTemplateConfig>({
    show_intro: false,
    intro_text: "",
    intro_duration_secs: 2.0,
    show_outro: false,
    outro_text: "",
    outro_duration_secs: 2.0,
    accent_color: "#22d3ee",
    font_family: "Inter",
  });
  const [templateSaving, setTemplateSaving] = useState(false);
  const [templateMsg, setTemplateMsg] = useState<string | null>(null);

  // Per-highlight captions toggle: default true
  const [captionsMap, setCaptionsMap] = useState<Map<string, boolean>>(new Map());

  const loadHighlights = useCallback(async (tab: FilterTab) => {
    setLoading(true);
    setError(null);
    try {
      const params: { status?: string; shorts_only?: boolean } = {};
      if (tab === "shorts") params.shorts_only = true;
      else if (tab === "approved") params.status = "approved";
      else if (tab === "rejected") params.status = "rejected";

      const res = await fetchCreatorHighlights(params);
      setHighlights(res.highlights);
    } catch (err) {
      setError(err instanceof ApiError ? err.detail : "Failed to load highlights");
    } finally {
      setLoading(false);
    }
  }, []);

  // Load shorts for all approved highlights
  const loadShortsForHighlights = useCallback(
    async (hls: HighlightCandidate[]) => {
      const approved = hls.filter((h) => h.status === "approved");
      const newMap = new Map<string, GeneratedShort[]>();

      await Promise.all(
        approved.map(async (h) => {
          try {
            const res = await fetchShorts(h.id);
            newMap.set(h.id, res.shorts);
          } catch {
            // Non-critical — leave empty
            newMap.set(h.id, []);
          }
        }),
      );

      setShortsMap(newMap);
    },
    [],
  );

  useEffect(() => {
    loadHighlights(activeTab);
  }, [activeTab, loadHighlights]);

  // After highlights load, fetch shorts for approved ones
  useEffect(() => {
    if (highlights.length > 0) {
      loadShortsForHighlights(highlights);
    }
  }, [highlights, loadShortsForHighlights]);

  // Polling: when any highlight has processing shorts, poll every 5s
  useEffect(() => {
    const anyProcessing = Array.from(shortsMap.values()).some(hasProcessingShorts);

    if (anyProcessing) {
      if (!pollRef.current) {
        pollRef.current = setInterval(() => {
          // Refresh shorts for highlights that have processing items
          const processingIds = Array.from(shortsMap.entries())
            .filter(([, shorts]) => hasProcessingShorts(shorts))
            .map(([id]) => id);

          Promise.all(
            processingIds.map(async (id) => {
              try {
                const res = await fetchShorts(id);
                setShortsMap((prev) => {
                  const next = new Map(prev);
                  next.set(id, res.shorts);
                  return next;
                });
              } catch {
                // ignore poll errors
              }
            }),
          );
        }, POLL_INTERVAL_MS);
      }
    } else {
      if (pollRef.current) {
        clearInterval(pollRef.current);
        pollRef.current = null;
      }
    }

    return () => {
      if (pollRef.current) {
        clearInterval(pollRef.current);
        pollRef.current = null;
      }
    };
  }, [shortsMap]);

  // Load template config on mount if the user has a creator_id
  useEffect(() => {
    if (!user?.creator_id) return;
    fetchShortsTemplate(user.creator_id)
      .then(setTemplate)
      .catch(() => {
        // Non-critical — keep defaults
      });
  }, [user?.creator_id]);

  const handleSaveTemplate = async () => {
    if (!user?.creator_id) return;
    setTemplateSaving(true);
    setTemplateMsg(null);
    try {
      const saved = await updateShortsTemplate(user.creator_id, template);
      setTemplate(saved);
      setTemplateMsg("Template saved");
      setTimeout(() => setTemplateMsg(null), 2000);
    } catch (err) {
      setTemplateMsg(
        err instanceof ApiError ? err.detail : "Failed to save template",
      );
    } finally {
      setTemplateSaving(false);
    }
  };

  const handleTabChange = (tab: FilterTab) => {
    setActiveTab(tab);
    setExpandedId(null);
  };

  const handleApprove = async (id: string) => {
    setActionLoading(id);
    try {
      await updateHighlightStatus(id, "approved");
      await loadHighlights(activeTab);
    } catch (err) {
      setError(err instanceof ApiError ? err.detail : "Failed to update status");
    } finally {
      setActionLoading(null);
    }
  };

  const handleReject = async (id: string) => {
    setActionLoading(id);
    try {
      await updateHighlightStatus(id, "rejected");
      await loadHighlights(activeTab);
    } catch (err) {
      setError(err instanceof ApiError ? err.detail : "Failed to update status");
    } finally {
      setActionLoading(null);
    }
  };

  const handleToggleTrim = async (h: HighlightCandidate) => {
    if (expandedId === h.id) {
      setExpandedId(null);
      return;
    }
    // Fetch full detail to get score_breakdown
    try {
      const detail = await fetchHighlightDetail(h.id);
      setHighlights((prev) =>
        prev.map((x) => (x.id === h.id ? detail : x)),
      );
    } catch {
      // non-critical — proceed with what we have
    }
    setExpandedId(h.id);
    setTrimStart(
      h.trim_start != null
        ? String(h.trim_start)
        : h.key_moment
          ? String(h.key_moment.start_time)
          : "0",
    );
    setTrimEnd(
      h.trim_end != null
        ? String(h.trim_end)
        : h.key_moment
          ? String(h.key_moment.end_time)
          : "0",
    );
  };

  const handleSaveTrim = async (id: string) => {
    const start = parseFloat(trimStart);
    const end = parseFloat(trimEnd);
    if (isNaN(start) || isNaN(end) || start >= end || start < 0) {
      setError("Invalid trim values — start must be less than end, both ≥ 0");
      return;
    }
    setActionLoading(id);
    try {
      await trimHighlight(id, start, end);
      setExpandedId(null);
      await loadHighlights(activeTab);
    } catch (err) {
      setError(err instanceof ApiError ? err.detail : "Failed to save trim");
    } finally {
      setActionLoading(null);
    }
  };

  const handleGenerateShorts = async (highlightId: string) => {
    setGeneratingIds((prev) => new Set(prev).add(highlightId));
    setError(null);
    const captions = captionsMap.get(highlightId) ?? true;
    try {
      await generateShorts(highlightId, captions);
      // Immediately fetch shorts to show pending status
      const res = await fetchShorts(highlightId);
      setShortsMap((prev) => {
        const next = new Map(prev);
        next.set(highlightId, res.shorts);
        return next;
      });
    } catch (err) {
      setError(
        err instanceof ApiError ? err.detail : "Failed to dispatch shorts generation",
      );
    } finally {
      setGeneratingIds((prev) => {
        const next = new Set(prev);
        next.delete(highlightId);
        return next;
      });
    }
  };

  const handleDownload = async (shortId: string) => {
    try {
      const res = await getShortDownloadUrl(shortId);
      window.open(res.download_url, "_blank");
    } catch (err) {
      setError(
        err instanceof ApiError ? err.detail : "Failed to get download URL",
      );
    }
  };

  const handleCopyShareLink = async (s: GeneratedShort) => {
    const url = `${window.location.origin}/shorts/${s.share_token}`;
    const ok = await copyToClipboard(url);
    if (ok) {
      setCopiedShort({ id: s.id, kind: "share" });
      setTimeout(() => setCopiedShort(null), 2000);
    }
  };

  const handleCopyEmbed = async (s: GeneratedShort) => {
    const src = `${window.location.origin}/shorts/${s.share_token}`;
    const snippet = `<iframe src="${src}" width="${s.width}" height="${s.height}" frameborder="0" allowfullscreen></iframe>`;
    const ok = await copyToClipboard(snippet);
    if (ok) {
      setCopiedShort({ id: s.id, kind: "embed" });
      setTimeout(() => setCopiedShort(null), 2000);
    }
  };

  const tabs: { key: FilterTab; label: string }[] = [
    { key: "all", label: "All" },
    { key: "shorts", label: "Shorts" },
    { key: "approved", label: "Approved" },
    { key: "rejected", label: "Rejected" },
  ];

  return (
    <div className={styles.layout}>
      <SidebarNav />
      <div className={styles.content}>
        <h1 className={styles.pageTitle}>Highlight Queue</h1>
        <p className={styles.subtitle}>Review, trim, and approve auto-detected highlights</p>

        {/* Filter tabs */}
        <div className={styles.filterTabs}>
          {tabs.map((t) => (
            <button
              key={t.key}
              className={`${styles.filterTab}${activeTab === t.key ? ` ${styles.filterTabActive}` : ""}`}
              onClick={() => handleTabChange(t.key)}
            >
              {t.label}
            </button>
          ))}
        </div>

        {/* Template config collapsible section */}
        {user?.creator_id && (
          <div className={styles.templateSection}>
            <button
              className={styles.templateToggle}
              onClick={() => setTemplateOpen((v) => !v)}
            >
              <span>Shorts Template</span>
              <span className={styles.templateChevron}>
                {templateOpen ? "▾" : "▸"}
              </span>
            </button>
            {templateOpen && (
              <div className={styles.templateBody}>
                <div className={styles.templateGrid}>
                  {/* Intro */}
                  <div className={styles.templateGroup}>
                    <label className={styles.templateLabel}>
                      <input
                        type="checkbox"
                        checked={template.show_intro}
                        onChange={(e) =>
                          setTemplate((t) => ({ ...t, show_intro: e.target.checked }))
                        }
                      />
                      Show Intro
                    </label>
                    <input
                      type="text"
                      className={styles.templateInput}
                      placeholder="Intro text"
                      maxLength={100}
                      value={template.intro_text}
                      onChange={(e) =>
                        setTemplate((t) => ({ ...t, intro_text: e.target.value }))
                      }
                      disabled={!template.show_intro}
                    />
                    <label className={styles.templateRangeLabel}>
                      Duration: {template.intro_duration_secs.toFixed(1)}s
                      <input
                        type="range"
                        min={1}
                        max={5}
                        step={0.5}
                        value={template.intro_duration_secs}
                        onChange={(e) =>
                          setTemplate((t) => ({
                            ...t,
                            intro_duration_secs: parseFloat(e.target.value),
                          }))
                        }
                        disabled={!template.show_intro}
                      />
                    </label>
                  </div>

                  {/* Outro */}
                  <div className={styles.templateGroup}>
                    <label className={styles.templateLabel}>
                      <input
                        type="checkbox"
                        checked={template.show_outro}
                        onChange={(e) =>
                          setTemplate((t) => ({ ...t, show_outro: e.target.checked }))
                        }
                      />
                      Show Outro
                    </label>
                    <input
                      type="text"
                      className={styles.templateInput}
                      placeholder="Outro text"
                      maxLength={100}
                      value={template.outro_text}
                      onChange={(e) =>
                        setTemplate((t) => ({ ...t, outro_text: e.target.value }))
                      }
                      disabled={!template.show_outro}
                    />
                    <label className={styles.templateRangeLabel}>
                      Duration: {template.outro_duration_secs.toFixed(1)}s
                      <input
                        type="range"
                        min={1}
                        max={5}
                        step={0.5}
                        value={template.outro_duration_secs}
                        onChange={(e) =>
                          setTemplate((t) => ({
                            ...t,
                            outro_duration_secs: parseFloat(e.target.value),
                          }))
                        }
                        disabled={!template.show_outro}
                      />
                    </label>
                  </div>

                  {/* Style */}
                  <div className={styles.templateGroup}>
                    <label className={styles.templateRangeLabel}>
                      Accent Color
                      <input
                        type="color"
                        value={template.accent_color}
                        onChange={(e) =>
                          setTemplate((t) => ({ ...t, accent_color: e.target.value }))
                        }
                        className={styles.colorInput}
                      />
                    </label>
                    <label className={styles.templateRangeLabel}>
                      Font
                      <input
                        type="text"
                        className={styles.templateInput}
                        value={template.font_family}
                        onChange={(e) =>
                          setTemplate((t) => ({ ...t, font_family: e.target.value }))
                        }
                        maxLength={50}
                      />
                    </label>
                  </div>
                </div>
                <div className={styles.templateActions}>
                  <button
                    className={`${styles.actionBtn} ${styles.approveBtn}`}
                    onClick={handleSaveTemplate}
                    disabled={templateSaving}
                  >
                    {templateSaving ? "Saving…" : "Save Template"}
                  </button>
                  {templateMsg && (
                    <span className={styles.templateMsg}>{templateMsg}</span>
                  )}
                </div>
              </div>
            )}
          </div>
        )}

        {/* Error */}
        {error && <div className={styles.errorState}>{error}</div>}

        {/* Loading */}
        {loading && <div className={styles.loadingState}>Loading highlights…</div>}

        {/* Empty */}
        {!loading && !error && highlights.length === 0 && (
          <div className={styles.emptyState}>
            <h2>No highlights found</h2>
            <p>
              {activeTab === "all"
                ? "No highlight candidates have been detected yet."
                : `No ${activeTab === "shorts" ? "short (≤ 60 s)" : activeTab} highlights.`}
            </p>
          </div>
        )}

        {/* Candidate list */}
        {!loading && highlights.length > 0 && (
          <div className={styles.candidateList}>
            {highlights.map((h) => {
              const shorts = shortsMap.get(h.id) ?? [];
              const isGenerating = generatingIds.has(h.id);
              const showGenerateBtn =
                h.status === "approved" && canGenerateShorts(shorts);
              const showShortsStatus = shorts.length > 0;

              return (
                <div key={h.id} className={styles.candidateCard}>
                  {/* Header */}
                  <div className={styles.candidateHeader}>
                    <span className={styles.candidateTitle}>
                      {h.key_moment?.title ?? "Untitled highlight"}
                    </span>
                    <span className={styles.candidateDuration}>
                      {formatDuration(h.duration_secs)}
                    </span>
                    {h.duration_secs <= 60 && (
                      <span className={styles.shortsBadge}>Short</span>
                    )}
                    <span className={`${styles.badge} ${statusBadgeClass(h.status)}`}>
                      {h.status}
                    </span>
                  </div>

                  {/* Composite score */}
                  <div className={styles.compositeScore}>
                    <span className={styles.compositeLabel}>
                      {Math.round(h.score * 100)}%
                    </span>
                    <div className={styles.scoreBarTrack}>
                      <div
                        className={styles.scoreBarFill}
                        style={{ width: `${Math.round(h.score * 100)}%` }}
                      />
                    </div>
                  </div>

                  {/* Score breakdown (shown when expanded) */}
                  {expandedId === h.id && h.score_breakdown && (
                    <div className={styles.breakdownSection}>
                      {BREAKDOWN_LABELS.map(({ key, label }) => {
                        const val = h.score_breakdown![key];
                        return (
                          <div key={key} className={styles.breakdownRow}>
                            <span className={styles.breakdownLabel}>{label}</span>
                            <div className={styles.breakdownBar}>
                              <div
                                className={styles.breakdownBarFill}
                                style={{ width: `${Math.round(val * 100)}%` }}
                              />
                            </div>
                            <span className={styles.breakdownValue}>
                              {Math.round(val * 100)}%
                            </span>
                          </div>
                        );
                      })}
                    </div>
                  )}

                  {/* Shorts status badges */}
                  {showShortsStatus && (
                    <div className={styles.shortsSection}>
                      <span className={styles.shortsLabel}>Shorts</span>
                      <div className={styles.shortsBadges}>
                        {shorts.map((s) => (
                          <div key={s.id} className={styles.shortItem}>
                            <span
                              className={`${styles.shortBadge} ${shortStatusClass(s.status)}`}
                            >
                              {formatPresetLabel(s.format_preset)}{" "}
                              {s.status}
                            </span>
                            {s.status === "complete" && (
                              <>
                                <button
                                  className={styles.downloadLink}
                                  onClick={() => handleDownload(s.id)}
                                  title="Download"
                                >
                                  ↓
                                </button>
                                {s.share_token && (
                                  <>
                                    <button
                                      className={`${styles.downloadLink} ${copiedShort?.id === s.id && copiedShort.kind === "share" ? styles.copiedFlash : ""}`}
                                      onClick={() => handleCopyShareLink(s)}
                                      title="Copy share link"
                                    >
                                      {copiedShort?.id === s.id && copiedShort.kind === "share" ? "✓" : "🔗"}
                                    </button>
                                    <button
                                      className={`${styles.downloadLink} ${copiedShort?.id === s.id && copiedShort.kind === "embed" ? styles.copiedFlash : ""}`}
                                      onClick={() => handleCopyEmbed(s)}
                                      title="Copy embed code"
                                    >
                                      {copiedShort?.id === s.id && copiedShort.kind === "embed" ? "✓" : "⧉"}
                                    </button>
                                  </>
                                )}
                              </>
                            )}
                            {s.status === "failed" && s.error_message && (
                              <span
                                className={styles.shortError}
                                title={s.error_message}
                              >
                                ⚠
                              </span>
                            )}
                          </div>
                        ))}
                      </div>
                    </div>
                  )}

                  {/* Action buttons */}
                  <div className={styles.actions}>
                    <button
                      className={`${styles.actionBtn} ${styles.approveBtn}`}
                      disabled={actionLoading === h.id || h.status === "approved"}
                      onClick={() => handleApprove(h.id)}
                    >
                      Approve
                    </button>
                    <button
                      className={`${styles.actionBtn} ${styles.rejectBtn}`}
                      disabled={actionLoading === h.id || h.status === "rejected"}
                      onClick={() => handleReject(h.id)}
                    >
                      Discard
                    </button>
                    <button
                      className={styles.actionBtn}
                      disabled={actionLoading === h.id}
                      onClick={() => handleToggleTrim(h)}
                    >
                      {expandedId === h.id ? "Close" : "Trim"}
                    </button>
                    {showGenerateBtn && (
                      <>
                        <label className={styles.captionToggle}>
                          <input
                            type="checkbox"
                            checked={captionsMap.get(h.id) ?? true}
                            onChange={(e) =>
                              setCaptionsMap((prev) => {
                                const next = new Map(prev);
                                next.set(h.id, e.target.checked);
                                return next;
                              })
                            }
                          />
                          Captions
                        </label>
                        <button
                          className={`${styles.actionBtn} ${styles.generateBtn}`}
                          disabled={isGenerating}
                          onClick={() => handleGenerateShorts(h.id)}
                        >
                          {isGenerating ? "Generating…" : "Generate Shorts"}
                        </button>
                      </>
                    )}
                  </div>

                  {/* Trim panel */}
                  {expandedId === h.id && (
                    <div className={styles.trimPanel}>
                      <div className={styles.trimField}>
                        <span className={styles.trimLabel}>Start (s)</span>
                        <input
                          type="number"
                          className={styles.trimInput}
                          value={trimStart}
                          onChange={(e) => setTrimStart(e.target.value)}
                          min={0}
                          step={0.1}
                        />
                      </div>
                      <div className={styles.trimField}>
                        <span className={styles.trimLabel}>End (s)</span>
                        <input
                          type="number"
                          className={styles.trimInput}
                          value={trimEnd}
                          onChange={(e) => setTrimEnd(e.target.value)}
                          min={0}
                          step={0.1}
                        />
                      </div>
                      <div className={styles.trimActions}>
                        <button
                          className={`${styles.actionBtn} ${styles.approveBtn}`}
                          disabled={actionLoading === h.id}
                          onClick={() => handleSaveTrim(h.id)}
                        >
                          Save
                        </button>
                        <button
                          className={styles.actionBtn}
                          onClick={() => setExpandedId(null)}
                        >
                          Cancel
                        </button>
                      </div>
                    </div>
                  )}
                </div>
              );
            })}
          </div>
        )}
      </div>
    </div>
  );
}
