'use client';

import { useCallback, useEffect, useRef, useState } from 'react';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import {
  DndContext,
  DragEndEvent,
  DragOverEvent,
  DragStartEvent,
  DragOverlay,
  PointerSensor,
  useSensor,
  useSensors,
  closestCenter,
} from '@dnd-kit/core';
import { arrayMove, SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
import CounterCard, { Counter } from './components/CounterCard';
import CounterModal, { Group } from './components/CounterModal';
import CounterDetailModal, { HistoryData } from './components/CounterDetailModal';
import GroupSection from './components/GroupSection';
import SortableGroupSection from './components/SortableGroupSection';

export default function Home() {
  const router = useRouter();
  const [counters, setCounters] = useState<Counter[]>([]);
  const [groups, setGroups] = useState<Group[]>([]);
  const [modalOpen, setModalOpen] = useState(false);
  const [editingCounter, setEditingCounter] = useState<Counter | null>(null);
  const [activeCounter, setActiveCounter] = useState<Counter | null>(null);
  const [activeGroup, setActiveGroup] = useState<Group | null>(null);
  const [newGroupName, setNewGroupName] = useState('');
  const [addingGroup, setAddingGroup] = useState(false);
  const [loading, setLoading] = useState(true);
  const [historyCounterId, setHistoryCounterId] = useState<number | null>(null);
  const [editMode, setEditMode] = useState(false);

  // Always-current ref so drag handlers never read stale closure state
  const countersRef = useRef(counters);
  countersRef.current = counters;

  // Pre-fetch cache for history modal
  const historyCache = useRef<Map<number, HistoryData>>(new Map());
  const handlePrefetch = useCallback((id: number) => {
    if (historyCache.current.has(id)) return;
    fetch(`/api/counters/${id}/history`)
      .then(r => r.json())
      .then(d => historyCache.current.set(id, d))
      .catch(() => {});
  }, []);

  const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 6 } }));

  // ── Data fetching ──────────────────────────────────────────────────────────
  async function load() {
    try {
      const [cRes, gRes] = await Promise.all([fetch('/api/counters'), fetch('/api/groups')]);
      const [c, g] = await Promise.all([cRes.json(), gRes.json()]);
      setCounters(c);
      setGroups(g);
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => { load(); }, []);
  useEffect(() => { router.prefetch('/stats'); }, [router]);

  // ── Optimistic increment/decrement ─────────────────────────────────────────
  const handleIncrement = useCallback(async (id: number) => {
    setCounters(prev => prev.map(c => c.id === id ? { ...c, value: c.value + 1 } : c));
    const res = await fetch(`/api/counters/${id}/increment`, { method: 'POST' });
    if (!res.ok) setCounters(prev => prev.map(c => c.id === id ? { ...c, value: c.value - 1 } : c));
  }, []);

  const handleDecrement = useCallback(async (id: number) => {
    const counter = countersRef.current.find(c => c.id === id);
    if (!counter || counter.value <= 0) return;
    setCounters(prev => prev.map(c => c.id === id ? { ...c, value: c.value - 1 } : c));
    const res = await fetch(`/api/counters/${id}/decrement`, { method: 'POST' });
    if (!res.ok) setCounters(prev => prev.map(c => c.id === id ? { ...c, value: c.value + 1 } : c));
  }, []);

  // ── Create / Edit counter ──────────────────────────────────────────────────
  async function handleSaveCounter(data: { name: string; value: number; group_id: number | null; image_path: string | null }) {
    if (editingCounter) {
      // Optimistic update — close immediately, patch in background
      const optimistic = { ...editingCounter, ...data };
      setCounters(prev => prev.map(c => c.id === editingCounter.id ? optimistic : c));
      setModalOpen(false);
      setEditingCounter(null);
      const res = await fetch(`/api/counters/${editingCounter.id}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data),
      });
      if (res.ok) {
        const updated = await res.json();
        setCounters(prev => prev.map(c => c.id === updated.id ? updated : c));
      } else {
        // Roll back
        setCounters(prev => prev.map(c => c.id === editingCounter.id ? editingCounter : c));
      }
    } else {
      // Optimistic create with a temporary id
      const tempId = -Date.now();
      const optimistic = { ...data, id: tempId, order_index: 0 };
      setCounters(prev => [...prev, optimistic]);
      setModalOpen(false);
      setEditingCounter(null);
      const res = await fetch('/api/counters', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data),
      });
      if (res.ok) {
        const created = await res.json();
        setCounters(prev => prev.map(c => c.id === tempId ? created : c));
      } else {
        // Roll back
        setCounters(prev => prev.filter(c => c.id !== tempId));
      }
    }
  }

  // ── Delete counter ─────────────────────────────────────────────────────────
  async function handleDeleteCounter(id: number) {
    const prev = counters.find(c => c.id === id);
    setCounters(cs => cs.filter(c => c.id !== id));
    const res = await fetch(`/api/counters/${id}`, { method: 'DELETE' });
    if (!res.ok && prev) setCounters(cs => [...cs, prev].sort((a, b) => a.order_index - b.order_index));
  }

  // ── Groups ─────────────────────────────────────────────────────────────────
  async function handleCreateGroup() {
    if (!newGroupName.trim()) return;
    const res = await fetch('/api/groups', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name: newGroupName.trim() }),
    });
    const created = await res.json();
    setGroups(prev => [...prev, created]);
    setNewGroupName('');
    setAddingGroup(false);
  }

  async function handleRenameGroup(group: Group) {
    const res = await fetch(`/api/groups/${group.id}`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name: group.name }),
    });
    const updated = await res.json();
    setGroups(prev => prev.map(g => g.id === group.id ? updated : g));
  }

  async function handleDeleteGroup(id: number) {
    setGroups(prev => prev.filter(g => g.id !== id));
    setCounters(prev => prev.map(c => c.group_id === id ? { ...c, group_id: null } : c));
    await fetch(`/api/groups/${id}`, { method: 'DELETE' });
  }

  // ── Drag and drop ──────────────────────────────────────────────────────────
  function handleDragStart({ active }: DragStartEvent) {
    if (active.data.current?.type === 'group') {
      setActiveGroup(groups.find(g => `grp-${g.id}` === String(active.id)) ?? null);
      setActiveCounter(null);
    } else {
      setActiveCounter(countersRef.current.find(c => c.id === active.id) ?? null);
      setActiveGroup(null);
    }
  }

  function handleDragOver({ active, over }: DragOverEvent) {
    if (active.data.current?.type === 'group') return;
    if (!over) return;
    const activeId = active.id as number;
    const overId = over.id as string | number;

    let targetGroupId: number | null = null;
    if (typeof overId === 'string' && overId.startsWith('group-')) {
      targetGroupId = Number(overId.replace('group-', ''));
    } else if (overId === 'ungrouped') {
      targetGroupId = null;
    } else {
      const overCounter = countersRef.current.find(c => c.id === overId);
      if (overCounter) targetGroupId = overCounter.group_id;
    }

    const activeC = countersRef.current.find(c => c.id === activeId);
    if (!activeC) return;
    if (activeC.group_id === targetGroupId) return;
    setCounters(prev => prev.map(c => c.id === activeId ? { ...c, group_id: targetGroupId } : c));
  }

  function handleDragEnd({ active, over }: DragEndEvent) {
    setActiveCounter(null);
    setActiveGroup(null);
    if (!over) return;

    // Group reorder
    if (active.data.current?.type === 'group') {
      const activeIdx = groups.findIndex(g => `grp-${g.id}` === String(active.id));
      const overIdx = groups.findIndex(g => `grp-${g.id}` === String(over.id));
      if (activeIdx === -1 || overIdx === -1 || activeIdx === overIdx) return;
      setGroups(arrayMove(groups, activeIdx, overIdx).map((g, i) => ({ ...g, order_index: i })));
      return;
    }

    // Counter reorder
    const activeId = active.id as number;
    const overId = over.id as string | number;

    if (typeof overId === 'string') {
      let targetGroupId: number | null = null;
      if (overId.startsWith('group-')) targetGroupId = Number(overId.replace('group-', ''));
      setCounters(prev => prev.map(c => c.id === activeId ? { ...c, group_id: targetGroupId } : c));
      return;
    }

    setCounters(prev => {
      const activeIdx = prev.findIndex(c => c.id === activeId);
      const overIdx = prev.findIndex(c => c.id === (overId as number));
      if (activeIdx === -1 || overIdx === -1 || activeIdx === overIdx) return prev;
      const targetGroupId = prev[overIdx].group_id;
      return arrayMove(prev, activeIdx, overIdx).map((c, i) => ({
        ...c,
        order_index: i,
        group_id: c.id === activeId ? targetGroupId : c.group_id,
      }));
    });
  }

  // ── Derived data ───────────────────────────────────────────────────────────
  const ungrouped = counters.filter(c => c.group_id === null);

  if (loading) {
    return (
      <main className="min-h-screen bg-ctp-base px-4 py-8">
        <div className="max-w-7xl mx-auto">
          <div className="flex items-center justify-between mb-8 flex-wrap gap-4">
            <h1 className="text-3xl font-extrabold text-ctp-text tracking-tight">Tally counters</h1>
            <div className="flex gap-3 items-center">
              {[16, 24, 16, 28].map((w, i) => (
                <div key={i} className={`h-9 w-${w} rounded-lg bg-ctp-surface0 animate-pulse`} />
              ))}
            </div>
          </div>
          <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-3">
            {Array.from({ length: 10 }).map((_, i) => (
              <div key={i} className="bg-ctp-surface0 rounded-2xl h-52 animate-pulse" />
            ))}
          </div>
        </div>
      </main>
    );
  }

  return (
    <main className="min-h-screen bg-ctp-base px-4 py-8">
      <div className="max-w-7xl mx-auto">
        {/* Header */}
        <div className="flex items-center justify-between mb-8 flex-wrap gap-4">
          <h1 className="text-3xl font-extrabold text-ctp-text tracking-tight">Tally counters</h1>
          <div className="flex gap-3 flex-wrap items-center">
            <Link
              href="/stats"
              className="flex items-center gap-1.5 px-4 py-2 text-sm rounded-lg border border-ctp-surface1 text-ctp-subtext1 hover:bg-ctp-surface0 transition-colors"
            >
              <svg xmlns="http://www.w3.org/2000/svg" className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                <line x1="18" y1="20" x2="18" y2="10" />
                <line x1="12" y1="20" x2="12" y2="4" />
                <line x1="6" y1="20" x2="6" y2="14" />
              </svg>
              Stats
            </Link>
            {addingGroup ? (
              <div className="flex gap-2">
                <input
                  autoFocus
                  value={newGroupName}
                  onChange={e => setNewGroupName(e.target.value)}
                  onKeyDown={e => { if (e.key === 'Enter') handleCreateGroup(); if (e.key === 'Escape') { setAddingGroup(false); setNewGroupName(''); } }}
                  placeholder="Group name…"
                  className="rounded-lg border border-ctp-surface1 bg-ctp-surface0 text-ctp-text px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ctp-mauve"
                />
                <button onClick={handleCreateGroup} className="px-3 py-2 text-sm rounded-lg bg-ctp-mauve hover:bg-ctp-lavender text-ctp-base font-medium transition-colors">Add</button>
                <button onClick={() => { setAddingGroup(false); setNewGroupName(''); }} className="px-3 py-2 text-sm rounded-lg border border-ctp-surface1 text-ctp-subtext1 hover:bg-ctp-surface0 transition-colors">Cancel</button>
              </div>
            ) : (
              <button onClick={() => setAddingGroup(true)} className="px-4 py-2 text-sm rounded-lg border border-ctp-surface1 text-ctp-subtext1 hover:bg-ctp-surface0 transition-colors">
                + New Group
              </button>
            )}
            <button
              onClick={() => {
                if (editMode) {
                  // Persist all reorder/group changes accumulated during edit mode
                  setEditMode(false);
                  fetch('/api/reorder', {
                    method: 'PUT',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                      counters: counters.map(c => ({ id: c.id, order_index: c.order_index, group_id: c.group_id })),
                      groups: groups.map(g => ({ id: g.id, order_index: g.order_index })),
                    }),
                  });
                } else {
                  setEditMode(true);
                }
              }}
              className={`px-4 py-2 text-sm rounded-lg border transition-colors ${
                editMode
                  ? 'border-ctp-mauve bg-ctp-mauve/10 text-ctp-mauve hover:bg-ctp-mauve/20'
                  : 'border-ctp-surface1 text-ctp-subtext1 hover:bg-ctp-surface0'
              }`}
            >
              {editMode ? 'Done' : 'Edit'}
            </button>
            <button
              onClick={() => { setEditingCounter(null); setModalOpen(true); }}
              className="px-4 py-2 text-sm rounded-lg bg-ctp-mauve hover:bg-ctp-lavender text-ctp-base font-medium transition-colors shadow-sm"
            >
              + Add Counter
            </button>
          </div>
        </div>

        {/* Board */}
        <DndContext
          sensors={sensors}
          collisionDetection={closestCenter}
          onDragStart={handleDragStart}
          onDragOver={handleDragOver}
          onDragEnd={handleDragEnd}
        >
          {/* Groups */}
          <SortableContext items={groups.map(g => `grp-${g.id}`)} strategy={verticalListSortingStrategy}>
            {groups.map(group => (
              <SortableGroupSection
                key={group.id}
                group={group}
                counters={counters.filter(c => c.group_id === group.id)}
                onIncrement={handleIncrement}
                onDecrement={handleDecrement}
                onEdit={c => { setEditingCounter(c); setModalOpen(true); }}
                onHistory={setHistoryCounterId}
                onPrefetch={handlePrefetch}
                editMode={editMode}
                onRenameGroup={handleRenameGroup}
                onDeleteGroup={handleDeleteGroup}
              />
            ))}
          </SortableContext>

          <GroupSection
            group={null}
            counters={ungrouped}
            onIncrement={handleIncrement}
            onDecrement={handleDecrement}
            onEdit={c => { setEditingCounter(c); setModalOpen(true); }}
            onHistory={setHistoryCounterId}
            onPrefetch={handlePrefetch}
            editMode={editMode}
          />

          <DragOverlay>
            {activeCounter && (
              <div className="rotate-2 scale-105 shadow-2xl">
                <CounterCard
                  counter={activeCounter}
                  onIncrement={() => {}}
                  onDecrement={() => {}}
                  onEdit={() => {}}
                  onHistory={() => {}}
                />
              </div>
            )}
            {activeGroup && (
              <div className="px-4 py-3 bg-ctp-mantle rounded-xl shadow-2xl ring-1 ring-ctp-mauve opacity-90">
                <span className="font-bold text-ctp-text">{activeGroup.name}</span>
              </div>
            )}
          </DragOverlay>
        </DndContext>

        {counters.length === 0 && (
          <div className="text-center mt-20">
            <p className="text-ctp-overlay0 text-lg">No counters yet.</p>
            <button
              onClick={() => setModalOpen(true)}
              className="mt-4 px-6 py-3 rounded-xl bg-ctp-mauve hover:bg-ctp-lavender text-ctp-base font-medium transition-colors shadow"
            >
              Create your first counter
            </button>
          </div>
        )}
      </div>

      <CounterModal
        open={modalOpen}
        initial={editingCounter}
        groups={groups}
        onClose={() => { setModalOpen(false); setEditingCounter(null); }}
        onSave={handleSaveCounter}
        onDelete={handleDeleteCounter}
      />

      <CounterDetailModal
        counterId={historyCounterId}
        cache={historyCache.current}
        onClose={() => setHistoryCounterId(null)}
      />
    </main>
  );
}
