"use client";
import React, { useEffect, useMemo, useState } from 'react';
import type { TcgCard } from '@/types/pokemon';
import { loadChecklistServer, saveChecklistServer } from '@/lib/checklist';
import type { ChecklistV2, VariantKey } from '@/lib/checklist';
import CardGrid from '@/components/CardGrid';
import Header from '@/components/Header';
import SetFilter from '@/components/SetFilter';

export default function Page() {
  const [cards, setCards] = useState<TcgCard[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [query, setQuery] = useState('');
  const [checklist, setChecklist] = useState<ChecklistV2>({});
  const [setId, setSetId] = useState('');
  const [note, setNote] = useState<string | null>(null);
  const [tab, setTab] = useState<'uncollected' | 'collected'>('uncollected');
  const [refreshing, setRefreshing] = useState(false);
  const [updatedAt, setUpdatedAt] = useState<string | null>(null);
  const [cachedFlag, setCachedFlag] = useState<boolean | null>(null);
  const [toast, setToast] = useState<string | null>(null);
  const [overrides, setOverrides] = useState<Record<string, boolean>>({});

  useEffect(() => {
    (async () => {
      const data = await loadChecklistServer();
      setChecklist(data);
    })();
  }, []);

  // Load reverse overrides at start
  useEffect(() => {
    (async () => {
      try {
        const res = await fetch('/api/magikarp/override', { cache: 'no-store' });
        if (!res.ok) return;
        const json = await res.json();
        const map = (json?.data?.reverseHolofoil || {}) as Record<string, boolean>;
        if (map && typeof map === 'object') setOverrides(map);
      } catch {}
    })();
    // Listen for UI-initiated override changes
    function onOverrideChanged(ev: Event) {
      try {
        const ce = ev as CustomEvent<{ id: string; reverse: boolean }>;
        const { id, reverse } = ce.detail || ({} as any);
        if (!id) return;
        setOverrides((prev) => ({ ...prev, [id]: !!reverse }));
      } catch {}
    }
    window.addEventListener('reverse-override-changed', onOverrideChanged as EventListener);
    return () => window.removeEventListener('reverse-override-changed', onOverrideChanged as EventListener);
  }, []);

  useEffect(() => {
    async function load() {
      setLoading(true);
      setError(null);
      try {
        const res = await fetch('/api/magikarp?pageSize=250');
        if (!res.ok) throw new Error('Failed to fetch');
        const json = await res.json();
        const list: TcgCard[] = json.data || [];
        list.sort((a, b) => {
          const da = Date.parse(a.set.releaseDate || '');
          const db = Date.parse(b.set.releaseDate || '');
          if (Number.isFinite(da) && Number.isFinite(db)) {
            if (da !== db) return da - db; // oldest first
          } else if (Number.isFinite(da)) {
            return -1;
          } else if (Number.isFinite(db)) {
            return 1;
          }
          // tie-breaker by card number if numeric
          const na = parseInt(a.number, 10);
          const nb = parseInt(b.number, 10);
          if (Number.isFinite(na) && Number.isFinite(nb)) return na - nb;
          return a.number.localeCompare(b.number);
        });
        setCards(list);
        if (json.note) setNote(String(json.note));
        if (json.updatedAt) setUpdatedAt(String(json.updatedAt));
        if (typeof json.cached === 'boolean') setCachedFlag(json.cached);
      } catch (e: any) {
        setError(e?.message || 'Error');
      } finally {
        setLoading(false);
      }
    }
    load();
  }, []);

  async function refreshCards() {
    setRefreshing(true);
    setError(null);
    try {
      const res = await fetch('/api/magikarp?pageSize=250&refresh=1', { cache: 'no-store' });
      if (!res.ok) throw new Error('Failed to refresh');
      const json = await res.json();
      const list: TcgCard[] = json.data || [];
      list.sort((a, b) => {
        const da = Date.parse(a.set.releaseDate || '');
        const db = Date.parse(b.set.releaseDate || '');
        if (Number.isFinite(da) && Number.isFinite(db)) {
          if (da !== db) return da - db; // oldest first
        } else if (Number.isFinite(da)) {
          return -1;
        } else if (Number.isFinite(db)) {
          return 1;
        }
        const na = parseInt(a.number, 10);
        const nb = parseInt(b.number, 10);
        if (Number.isFinite(na) && Number.isFinite(nb)) return na - nb;
        return a.number.localeCompare(b.number);
      });
      setCards(list);
      if (json.note) setNote(String(json.note)); else setNote(null);
      if (json.updatedAt) setUpdatedAt(String(json.updatedAt));
      if (typeof json.cached === 'boolean') setCachedFlag(json.cached);
    } catch (e: any) {
      // Non-blocking toast on refresh failure
      const msg = e?.message ? String(e.message) : 'Refresh failed';
      setToast(msg);
      // auto-hide
      setTimeout(() => setToast(null), 3000);
    } finally {
      setRefreshing(false);
    }
  }

  function toggleCollected(id: string, key: VariantKey) {
    setChecklist((prev) => {
      const next: ChecklistV2 = { ...prev };
      const current = { ...(next[id] || {}) };
      current[key] = !current[key];
      // Clean up empty records to keep storage tidy
      const hasAny = Object.values(current).some(Boolean);
      if (hasAny) next[id] = current; else delete next[id];
      // fire-and-forget save to server; fallback handled in lib
      void saveChecklistServer(next);
      return next;
    });
  }

  function availableVariants(card: TcgCard): VariantKey[] {
    const list: VariantKey[] = ['base'];
    const hasHolo = !!(card.variants?.holofoil || (card as any).tcgplayer?.prices?.holofoil);
    const hasReverse = !!(card.variants?.reverseHolofoil || (card as any).tcgplayer?.prices?.reverseHolofoil) || !!overrides[card.id];
    if (hasHolo) list.push('holofoil');
    if (hasReverse) list.push('reverseHolofoil');
    return list;
  }

  function isFullyCollected(card: TcgCard): boolean {
    const needed = availableVariants(card);
    const state = checklist[card.id] || {};
    return needed.every((k) => !!state[k]);
  }

  const filtered = useMemo(() => {
    const byQuery = (() => {
      if (!query.trim()) return cards;
      const q = query.toLowerCase();
      return cards.filter((c) =>
        c.name.toLowerCase().includes(q) ||
        c.number.toLowerCase().includes(q) ||
        (c.rarity || '').toLowerCase().includes(q) ||
        c.set.name.toLowerCase().includes(q) ||
        c.set.series.toLowerCase().includes(q)
      );
    })();
    const bySet = setId ? byQuery.filter((c) => c.set.id === setId) : byQuery;
    return bySet;
  }, [cards, query, setId]);

  // Variant-based counts for filtered set
  const filteredCollectedVariantsCount = useMemo(() => {
    return filtered.reduce((sum, c) => {
      const state = checklist[c.id] || {};
      return sum + availableVariants(c).reduce((acc, k) => acc + (state[k] ? 1 : 0), 0);
    }, 0);
  }, [filtered, checklist]);
  const filteredTotalVariants = useMemo(() => filtered.reduce((sum, c) => sum + availableVariants(c).length, 0), [filtered]);
  const filteredUncollectedVariantsCount = useMemo(() => filteredTotalVariants - filteredCollectedVariantsCount, [filteredTotalVariants, filteredCollectedVariantsCount]);

  const displayed = useMemo(() => {
    return tab === 'collected'
      ? filtered.filter((c) => isFullyCollected(c))
      : filtered.filter((c) => !isFullyCollected(c));
  }, [filtered, checklist, tab]);

  const setOptions = useMemo(() => {
    const map = new Map<string, string>();
    for (const c of cards) {
      if (!map.has(c.set.id)) map.set(c.set.id, `${c.set.series} — ${c.set.name}`);
    }
    return Array.from(map.entries()).map(([id, label]) => ({ id, label })).sort((a, b) => a.label.localeCompare(b.label));
  }, [cards]);

  // Overall variant-based totals for header
  const totalVariantsAll = useMemo(() => cards.reduce((sum, c) => sum + availableVariants(c).length, 0), [cards]);
  const collectedVariantsAll = useMemo(() => cards.reduce((sum, c) => {
    const state = checklist[c.id] || {};
    return sum + availableVariants(c).reduce((acc, k) => acc + (state[k] ? 1 : 0), 0);
  }, 0), [cards, checklist]);

  return (
    <main className="container mx-auto">
      <Header
        query={query}
        onQueryChange={setQuery}
        total={totalVariantsAll}
        collectedCount={collectedVariantsAll}
      />

      <div className="mb-4 flex flex-wrap items-center gap-3">
        <SetFilter options={setOptions} value={setId} onChange={setSetId} />
        <button
          type="button"
          onClick={refreshCards}
          disabled={refreshing}
          className={`px-3 py-1.5 text-sm rounded border transition ${refreshing ? 'bg-slate-200 text-slate-500 border-slate-300' : 'bg-white text-slate-700 border-slate-300 hover:bg-slate-50'}`}
          aria-busy={refreshing}
        >
          {refreshing ? 'Refreshing…' : 'Refresh cards'}
        </button>
        {updatedAt ? (
          <span className="text-xs text-slate-500 flex items-center gap-2">
            Updated: {new Date(updatedAt).toLocaleString()}
            {cachedFlag !== null && (
              <span className={`inline-flex items-center rounded px-1.5 py-0.5 text-[0.7rem] border ${cachedFlag ? 'bg-yellow-50 text-yellow-800 border-yellow-200' : 'bg-green-50 text-green-800 border-green-200'}`}>
                {cachedFlag ? 'Cached' : 'Live'}
              </span>
            )}
          </span>
        ) : null}
      </div>

      {loading ? (
        <p className="text-slate-600">Loading Magikarp cards…</p>
      ) : error ? (
        <p className="text-red-600">{error}</p>
      ) : (
        <>
          {note ? (
            <div className="mb-4 rounded-md border border-amber-300 bg-amber-50 p-3 text-amber-800 text-sm">
              {note}
            </div>
          ) : null}
          <div className="mb-3 flex items-center gap-2">
            <button
              type="button"
              onClick={() => setTab('uncollected')}
              className={`px-3 py-1.5 text-sm rounded border transition ${
                tab === 'uncollected'
                  ? 'bg-sky-600 text-white border-sky-600'
                  : 'bg-white text-slate-700 border-slate-300 hover:bg-slate-50'
              }`}
              aria-pressed={tab === 'uncollected'}
            >
              Uncollected <span className="ml-1 inline-block rounded bg-white/20 px-1.5 py-0.5 text-xs border border-white/30">
                {filteredUncollectedVariantsCount}
              </span>
            </button>
            <button
              type="button"
              onClick={() => setTab('collected')}
              className={`px-3 py-1.5 text-sm rounded border transition ${
                tab === 'collected'
                  ? 'bg-sky-600 text-white border-sky-600'
                  : 'bg-white text-slate-700 border-slate-300 hover:bg-slate-50'
              }`}
              aria-pressed={tab === 'collected'}
            >
              Collected <span className="ml-1 inline-block rounded bg-white/20 px-1.5 py-0.5 text-xs border border-white/30">
                {filteredCollectedVariantsCount}
              </span>
            </button>
          </div>
          <div className="mb-4 text-sm text-slate-600">
            Showing {displayed.length} of {filtered.length} cards in this tab.
          </div>
          <CardGrid cards={displayed} checklist={checklist} onToggle={toggleCollected} />
          {/* Toast */}
          {toast ? (
            <div className="fixed bottom-4 right-4 z-50 rounded-md bg-slate-900 text-white px-3 py-2 text-sm shadow-lg">
              {toast}
            </div>
          ) : null}
        </>
      )}
    </main>
  );
}
