import { useEffect, useRef, useState } from 'preact/hooks';
import { formatCents } from '../api';

async function j<T = any>(res: Response): Promise<T> {
  if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
  return res.json();
}

// Best-effort error message from a failed response ({ error } JSON or status text).
async function errText(res: Response): Promise<string> {
  try {
    return (await res.json()).error ?? res.statusText;
  } catch {
    return res.statusText;
  }
}

interface Drink { id: number; name: string; price_cents: number; archived: number }
interface BarRow { id: number; name: string; pfand_cents: number; drink_ids: number[] }
interface Totals { bar_id: number; bar_name: string; tx_count: number; paid_cents: number; crew_count: number; pfand_returns: number }
interface PerDrink { drink_id: number; drink_name: string; sold_qty: number }
interface ByDay { day: string; tx_count: number; paid_cents: number; crew_count: number; pfand_returns: number }

export function Admin() {
  const [authed, setAuthed] = useState<boolean | null>(null);

  useEffect(() => {
    fetch('/admin/api/me').then(j).then(r => setAuthed(r.authed)).catch(() => setAuthed(false));
  }, []);

  if (authed === null) return <div class="admin"><p>Lade…</p></div>;
  if (!authed) return <Login onAuthed={() => setAuthed(true)} />;
  return <Dashboard onLogout={() => setAuthed(false)} />;
}

function Login({ onAuthed }: { onAuthed: () => void }) {
  const [pw, setPw] = useState('');
  const [err, setErr] = useState<string | null>(null);

  async function submit(e: Event) {
    e.preventDefault();
    setErr(null);
    try {
      await fetch('/admin/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ password: pw }),
      }).then(j);
      onAuthed();
    } catch (e: any) {
      setErr(String(e));
    }
  }

  return (
    <form class="admin" onSubmit={submit}>
      <div class="login">
        <h1>Backoffice</h1>
        <input
          type="password"
          placeholder="Passwort"
          value={pw}
          onInput={(e: any) => setPw(e.currentTarget.value)}
        />
        {err && <div style="color:var(--danger)">{err}</div>}
        <button type="submit">Anmelden</button>
      </div>
    </form>
  );
}

function Dashboard({ onLogout }: { onLogout: () => void }) {
  return (
    <div class="admin">
      <div class="row" style="justify-content: space-between">
        <h1 style="margin:0">wutzcalc Backoffice</h1>
        <button onClick={async () => { await fetch('/admin/logout', { method: 'POST' }); onLogout(); }}>
          Abmelden
        </button>
      </div>
      <Stats />
      <Exports />
      <Drinks />
      <Bars />
    </div>
  );
}

function fmtDay(day: string): string {
  const [y, m, d] = day.split('-');
  return `${d}.${m}.${y}`;
}

function Stats() {
  const [data, setData] = useState<{ totals: Totals[]; per_drink: PerDrink[]; by_day: ByDay[] } | null>(null);
  function reload() { fetch('/admin/api/stats').then(j).then(setData); }
  useEffect(reload, []);

  async function reset() {
    if (!confirm('Wirklich die gesamte Statistik (alle Transaktionen) unwiderruflich löschen?')) return;
    await fetch('/admin/api/stats/reset', { method: 'POST' });
    reload();
  }

  if (!data) return <p>Lade Statistik…</p>;
  return (
    <>
      <div class="row" style="justify-content: space-between">
        <h2 style="margin:0">Umsatz nach Tagen</h2>
        <button class="danger" onClick={reset}>Statistik zurücksetzen</button>
      </div>
      <table>
        <thead><tr><th>Tag</th><th>Transaktionen</th><th>Bezahlt</th><th>Crew-Transaktionen</th><th>Pfand zurück</th></tr></thead>
        <tbody>
          {data.by_day.length === 0 && <tr><td colSpan={5} class="muted">Noch keine Verkäufe</td></tr>}
          {data.by_day.map(d => (
            <tr key={d.day}>
              <td>{fmtDay(d.day)}</td>
              <td>{d.tx_count}</td>
              <td>{formatCents(d.paid_cents)}</td>
              <td>{d.crew_count}</td>
              <td>{d.pfand_returns}</td>
            </tr>
          ))}
        </tbody>
      </table>
      <h2>Umsatz pro Bar</h2>
      <table>
        <thead><tr><th>Bar</th><th>Transaktionen</th><th>Bezahlt</th><th>Crew-Transaktionen</th><th>Pfand zurück</th></tr></thead>
        <tbody>
          {data.totals.map(t => (
            <tr key={t.bar_id}>
              <td>{t.bar_name}</td>
              <td>{t.tx_count}</td>
              <td>{formatCents(t.paid_cents)}</td>
              <td>{t.crew_count}</td>
              <td>{t.pfand_returns}</td>
            </tr>
          ))}
        </tbody>
      </table>
      <h2>Getränke</h2>
      <table>
        <thead><tr><th>Getränk</th><th>Verkauft</th></tr></thead>
        <tbody>
          {data.per_drink.map(d => (
            <tr key={d.drink_id}>
              <td>{d.drink_name}</td>
              <td>{d.sold_qty ?? 0}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </>
  );
}

function Exports() {
  return (
    <>
      <h2>CSV-Export</h2>
      <div class="row">
        <a href="/admin/api/export.csv?what=transactions"><button>Transaktionen</button></a>
        <a href="/admin/api/export.csv?what=items"><button>Positionen</button></a>
      </div>
    </>
  );
}

function Drinks() {
  const [list, setList] = useState<Drink[]>([]);
  const [name, setName] = useState('');
  const [price, setPrice] = useState('');

  function reload() { fetch('/admin/api/drinks').then(j).then(setList); }
  useEffect(reload, []);

  async function add() {
    const cents = Math.round(parseFloat(price) * 100);
    if (!name || !Number.isFinite(cents)) return;
    await fetch('/admin/api/drinks', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name, price_cents: cents }),
    });
    setName(''); setPrice(''); reload();
  }

  async function patch(id: number, body: Partial<Drink>) {
    await fetch(`/admin/api/drinks/${id}`, {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
    });
    reload();
  }

  async function del(d: Drink) {
    if (!confirm(`Getränk „${d.name}“ wirklich löschen?`)) return;
    const res = await fetch(`/admin/api/drinks/${d.id}`, { method: 'DELETE' });
    if (!res.ok) { alert(`Fehler: ${await errText(res)}`); return; }
    reload();
  }

  return (
    <>
      <h2>Getränke</h2>
      <table>
        <thead><tr><th>Name</th><th>Preis</th><th>Status</th><th></th></tr></thead>
        <tbody>
          {list.map(d => (
            <tr key={d.id}>
              <td>
                <input value={d.name} onChange={(e: any) => patch(d.id, { name: e.currentTarget.value })} />
              </td>
              <td>
                <input
                  type="number"
                  step="0.01"
                  value={(d.price_cents / 100).toFixed(2)}
                  onChange={(e: any) => patch(d.id, { price_cents: Math.round(parseFloat(e.currentTarget.value) * 100) })}
                />
              </td>
              <td class={d.archived ? 'muted' : ''}>{d.archived ? 'archiviert' : 'aktiv'}</td>
              <td>
                <div class="row" style="margin:0">
                  <button onClick={() => patch(d.id, { archived: !d.archived } as any)}>
                    {d.archived ? 'aktivieren' : 'archivieren'}
                  </button>
                  <button class="danger" onClick={() => del(d)}>löschen</button>
                </div>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
      <div class="row">
        <input placeholder="Name" value={name} onInput={(e: any) => setName(e.currentTarget.value)} />
        <input placeholder="Preis €" type="number" step="0.01" value={price} onInput={(e: any) => setPrice(e.currentTarget.value)} />
        <button onClick={add}>Hinzufügen</button>
      </div>
    </>
  );
}

function BarDrinkEditor({
  bar,
  allDrinks,
  onChange,
}: {
  bar: BarRow;
  allDrinks: Drink[];
  onChange: (ids: number[]) => void;
}) {
  const byId = new Map(allDrinks.map(d => [d.id, d]));
  const selected = bar.drink_ids.filter(id => {
    const d = byId.get(id);
    return d && !d.archived;
  });
  const available = allDrinks.filter(d => !d.archived && !selected.includes(d.id));

  const dragFrom = useRef<number | null>(null);
  const [dragOver, setDragOver] = useState<number | null>(null);

  function remove(idx: number) {
    onChange(selected.filter((_, i) => i !== idx));
  }
  function add(id: number) {
    onChange([...selected, id]);
  }
  function reorder(from: number, to: number) {
    if (from === to || from < 0 || to < 0 || from >= selected.length || to >= selected.length) return;
    const next = selected.slice();
    const [moved] = next.splice(from, 1);
    next.splice(to, 0, moved!);
    onChange(next);
  }

  return (
    <>
      <div style="margin-top:8px; font-size:14px; opacity:0.7">Aktive Getränke (zum Sortieren ziehen)</div>
      <ul class="dnd-list">
        {selected.length === 0 && <li class="muted">Keine</li>}
        {selected.map((id, idx) => {
          const d = byId.get(id);
          if (!d) return null;
          return (
            <li
              key={id}
              class={`dnd-item ${dragOver === idx ? 'drop-target' : ''}`}
              draggable
              onDragStart={(e: any) => {
                dragFrom.current = idx;
                e.dataTransfer.effectAllowed = 'move';
              }}
              onDragOver={(e: any) => {
                e.preventDefault();
                e.dataTransfer.dropEffect = 'move';
                if (dragOver !== idx) setDragOver(idx);
              }}
              onDragLeave={() => { if (dragOver === idx) setDragOver(null); }}
              onDrop={(e: any) => {
                e.preventDefault();
                const from = dragFrom.current;
                dragFrom.current = null;
                setDragOver(null);
                if (from != null) reorder(from, idx);
              }}
              onDragEnd={() => { dragFrom.current = null; setDragOver(null); }}
            >
              <span class="grip" aria-hidden="true">⋮⋮</span>
              <span class="dnd-name">{idx + 1}. {d.name}</span>
              <button onClick={() => remove(idx)}>×</button>
            </li>
          );
        })}
      </ul>
      {available.length > 0 && (
        <>
          <div style="font-size:14px; opacity:0.7">Hinzufügen</div>
          <div class="row">
            {available.map(d => (
              <button key={d.id} onClick={() => add(d.id)}>+ {d.name}</button>
            ))}
          </div>
        </>
      )}
    </>
  );
}

function Bars() {
  const [bars, setBars] = useState<BarRow[]>([]);
  const [drinks, setDrinks] = useState<Drink[]>([]);
  const [newName, setNewName] = useState('');

  function reload() {
    fetch('/admin/api/bars').then(j).then(setBars);
    fetch('/admin/api/drinks').then(j).then(setDrinks);
  }
  useEffect(reload, []);

  async function patch(id: number, body: Partial<BarRow>) {
    const res = await fetch(`/admin/api/bars/${id}`, {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
    });
    if (!res.ok) alert(`Fehler: ${await errText(res)}`);
    reload();
  }

  async function delBar(b: BarRow) {
    if (!confirm(`Tresen „${b.name}“ wirklich löschen?`)) return;
    const res = await fetch(`/admin/api/bars/${b.id}`, { method: 'DELETE' });
    if (!res.ok) { alert(`Fehler: ${await errText(res)}`); return; }
    reload();
  }

  async function addBar() {
    const name = newName.trim();
    if (!name) return;
    const res = await fetch('/admin/api/bars', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name, pfand_cents: 200 }),
    });
    if (!res.ok) {
      alert(`Fehler: ${await errText(res)}`);
      return;
    }
    setNewName('');
    reload();
  }

  return (
    <>
      <h2>Bars</h2>
      {bars.map(b => (
        <div key={b.id} style="margin-bottom:16px; padding:8px; border:1px solid var(--border); border-radius:6px">
          <div class="row">
            <label>
              Name
              <input
                value={b.name}
                onChange={(e: any) => patch(b.id, { name: e.currentTarget.value } as any)}
              />
            </label>
            <label>
              Pfand €
              <input
                type="number"
                step="0.01"
                value={(b.pfand_cents / 100).toFixed(2)}
                onChange={(e: any) =>
                  patch(b.id, { pfand_cents: Math.round(parseFloat(e.currentTarget.value) * 100) } as any)
                }
              />
            </label>
            <button class="danger" onClick={() => delBar(b)} style="margin-left:auto">Tresen löschen</button>
          </div>
          <BarDrinkEditor
            bar={b}
            allDrinks={drinks}
            onChange={(ids) => patch(b.id, { drink_ids: ids } as any)}
          />
        </div>
      ))}
      <div class="row">
        <input
          placeholder="Neue Bar"
          value={newName}
          onInput={(e: any) => setNewName(e.currentTarget.value)}
        />
        <button onClick={addBar}>Bar hinzufügen</button>
      </div>
    </>
  );
}
