import { useCallback, useEffect, useRef, useState } from "react";
import { apiGet, apiPost } from "../../api";
import { PageHead, StatCard, Loading, Empty, timeAgo } from "../../components/ui";
import {
  IconCheck,
  IconChevron,
  IconDisc,
  IconImage,
  IconLayers,
  IconRefresh,
  IconSearch,
  IconWand,
} from "../../components/icons";
import { useToast } from "../../lib/toast";

interface Overview {
  last_scan: any | null;
  last_metadata: any | null;
  scan_running: boolean;
  metadata_running: boolean;
  owned: number;
  missing: number;
  uncertain: number;
  ignored: number;
  completeness: number;
  library_artists: number;
  library_albums: number;
}
interface ArtistRow {
  id: number;
  name: string;
  owned: number;
  missing: number;
  uncertain: number;
  ignored: number;
  completeness: number;
}
interface Album {
  id: number;
  title: string;
  year: number;
  status: string;
  confidence: number;
  reason: string;
  source: string;
  manual_override: number;
}

const STATUS_BADGE: Record<string, string> = {
  owned: "badge-ok",
  probably_owned: "badge-ok",
  missing: "badge-bad",
  uncertain: "badge-warn",
  ignored: "badge",
};
const statusLabel = (s: string) => s.replace("_", " ");

export default function CollectionCompleteness() {
  const toast = useToast();
  const [overview, setOverview] = useState<Overview | null>(null);
  const [artists, setArtists] = useState<ArtistRow[]>([]);
  const [search, setSearch] = useState("");
  const [expanded, setExpanded] = useState<number | null>(null);
  const [albums, setAlbums] = useState<Record<number, Album[]>>({});
  const [loading, setLoading] = useState(true);
  const pollRef = useRef<number>();

  const loadOverview = useCallback(() => {
    return apiGet<Overview>("/api/music-collection/overview")
      .then(setOverview)
      .catch(() => setOverview(null));
  }, []);

  const loadArtists = useCallback(
    (q = "") =>
      apiGet<{ artists: ArtistRow[] }>(`/api/music-collection/artists?q=${encodeURIComponent(q)}`)
        .then((d) => setArtists(d.artists))
        .catch(() => setArtists([])),
    []
  );

  useEffect(() => {
    Promise.all([loadOverview(), loadArtists()]).finally(() => setLoading(false));
  }, [loadOverview, loadArtists]);

  // Poll while a job runs; refresh data when it finishes.
  const running = !!overview && (overview.scan_running || overview.metadata_running);
  useEffect(() => {
    if (!running) {
      window.clearInterval(pollRef.current);
      return;
    }
    pollRef.current = window.setInterval(async () => {
      const prev = running;
      await loadOverview();
      const next = overview && (overview.scan_running || overview.metadata_running);
      if (prev && !next) loadArtists(search);
    }, 2500);
    return () => window.clearInterval(pollRef.current);
  }, [running]); // eslint-disable-line react-hooks/exhaustive-deps

  async function startScan() {
    const res = await apiPost<{ started: boolean; reason?: string }>("/api/music-collection/scan");
    toast(res.started ? "Library scan started" : res.reason || "Already running", res.started ? "ok" : "info");
    loadOverview();
  }
  async function refreshMetadata() {
    const res = await apiPost<{ started: boolean; reason?: string }>("/api/music-collection/refresh-metadata");
    toast(res.started ? "Metadata refresh started" : res.reason || "Already running", res.started ? "ok" : "info");
    loadOverview();
  }

  function toggleArtist(id: number) {
    if (expanded === id) {
      setExpanded(null);
      return;
    }
    setExpanded(id);
    if (!albums[id]) {
      apiGet<{ albums: Album[] }>(`/api/music-collection/artist/${id}/albums`)
        .then((d) => setAlbums((a) => ({ ...a, [id]: d.albums })))
        .catch((e) => toast(e.message, "err"));
    }
  }

  async function decide(artistId: number, albumId: number, action: string) {
    try {
      await apiPost(`/api/music-collection/album/${albumId}/decision`, { action });
      const d = await apiGet<{ albums: Album[] }>(`/api/music-collection/artist/${artistId}/albums`);
      setAlbums((a) => ({ ...a, [artistId]: d.albums }));
      loadOverview();
      loadArtists(search);
    } catch (e: any) {
      toast(e.message, "err");
    }
  }

  const o = overview;
  const scanStatus = o?.scan_running
    ? "Scanning…"
    : o?.last_scan
    ? `${o.last_scan.status} · ${timeAgo(o.last_scan.completed_at || o.last_scan.started_at)}`
    : "Never run";

  return (
    <>
      <div className="row between" style={{ alignItems: "flex-start" }}>
        <PageHead title="Music Collection Completeness" icon={<IconDisc />} />
        <div className="row gap-sm">
          <button className="btn" onClick={startScan} disabled={o?.scan_running}>
            {o?.scan_running ? <span className="spinner" /> : <IconRefresh />} Scan library
          </button>
          <button className="btn btn-primary" onClick={refreshMetadata} disabled={o?.metadata_running}>
            {o?.metadata_running ? <span className="spinner" /> : <IconWand />} Refresh metadata
          </button>
        </div>
      </div>

      {loading ? (
        <Loading />
      ) : (
        <>
          <div className="stat-row" style={{ marginBottom: 14 }}>
            <StatCard icon={<IconCheck />} value={`${o?.completeness ?? 0}%`} label="Overall completeness" />
            <StatCard icon={<IconLayers />} value={o?.owned ?? 0} label="Owned albums" />
            <StatCard icon={<IconImage />} value={o?.missing ?? 0} label="Missing albums" />
            <StatCard icon={<IconDisc />} value={o?.uncertain ?? 0} label="Uncertain matches" />
          </div>

          <div className="row wrap gap-sm" style={{ marginBottom: 18 }}>
            <span className="badge">{o?.library_artists ?? 0} artists scanned</span>
            <span className="badge">{o?.library_albums ?? 0} albums in library</span>
            <span className="badge">Last scan: {scanStatus}</span>
            <span className="badge">
              Last metadata:{" "}
              {o?.metadata_running
                ? `running · ${o?.last_metadata?.progress || ""}`
                : o?.last_metadata
                ? timeAgo(o.last_metadata.completed_at || o.last_metadata.started_at)
                : "never"}
            </span>
          </div>

          <form
            className="search-inner"
            style={{ maxWidth: 360, marginBottom: 16 }}
            onSubmit={(e) => {
              e.preventDefault();
              loadArtists(search);
            }}
          >
            <IconSearch />
            <input className="input" placeholder="Search artists…" value={search} onChange={(e) => setSearch(e.target.value)} />
          </form>

          {artists.length === 0 ? (
            <div className="panel">
              <Empty icon={<IconDisc />}>
                No completeness data yet. Run <strong>Scan library</strong>, then <strong>Refresh metadata</strong> to
                compare against MusicBrainz.
              </Empty>
            </div>
          ) : (
            <div className="panel">
              {artists.map((a) => (
                <div key={a.id} style={{ borderBottom: "1px solid var(--border)" }}>
                  <button className="completeness-row" onClick={() => toggleArtist(a.id)}>
                    <IconChevron className={`nav-caret ${expanded === a.id ? "open" : ""}`} />
                    <span className="grow" style={{ textAlign: "left", fontWeight: 600 }}>
                      {a.name}
                    </span>
                    <span className="badge badge-ok">{a.owned} owned</span>
                    {a.missing > 0 && <span className="badge badge-bad">{a.missing} missing</span>}
                    {a.uncertain > 0 && <span className="badge badge-warn">{a.uncertain} uncertain</span>}
                    <span className="completeness-pct mono">{a.completeness}%</span>
                    <span className="bar" style={{ width: 90 }}>
                      <span className="bar-fill" style={{ width: `${a.completeness}%` }} />
                    </span>
                  </button>

                  {expanded === a.id && (
                    <div style={{ padding: "0 16px 14px 40px" }}>
                      {!albums[a.id] ? (
                        <Loading />
                      ) : (
                        <table className="data-table">
                          <thead>
                            <tr>
                              <th>Album</th>
                              <th>Year</th>
                              <th>Status</th>
                              <th>Confidence</th>
                              <th>Source</th>
                              <th style={{ textAlign: "right" }}>Actions</th>
                            </tr>
                          </thead>
                          <tbody>
                            {albums[a.id].map((al) => (
                              <tr key={al.id}>
                                <td className="cell-strong" title={al.reason}>
                                  {al.title}
                                  {al.manual_override ? <span className="badge" style={{ marginLeft: 8 }}>manual</span> : null}
                                </td>
                                <td className="mono">{al.year || "—"}</td>
                                <td>
                                  <span className={`badge ${STATUS_BADGE[al.status] || ""}`}>{statusLabel(al.status)}</span>
                                </td>
                                <td className="mono cell-sub">{al.confidence ? al.confidence.toFixed(2) : "—"}</td>
                                <td className="cell-sub">{al.source}</td>
                                <td>
                                  <div className="row gap-sm" style={{ justifyContent: "flex-end" }}>
                                    <button className="btn btn-sm" onClick={() => decide(a.id, al.id, "owned")}>
                                      Owned
                                    </button>
                                    <button className="btn btn-sm" onClick={() => decide(a.id, al.id, "missing")}>
                                      Missing
                                    </button>
                                    <button className="btn btn-sm" onClick={() => decide(a.id, al.id, "ignore")}>
                                      Ignore
                                    </button>
                                    <button className="btn btn-sm" onClick={() => decide(a.id, al.id, "reset")}>
                                      Reset
                                    </button>
                                  </div>
                                </td>
                              </tr>
                            ))}
                          </tbody>
                        </table>
                      )}
                    </div>
                  )}
                </div>
              ))}
            </div>
          )}
        </>
      )}
    </>
  );
}
