import { useMemo, useRef, useState } from 'preact/hooks';
import type { BarConfig, CartItem, Drink } from '@wutzcalc/shared';
import { api, formatCents, uuid } from '../api';

interface Props {
  config: BarConfig;
  onChangeBar: () => void;
}

type Line = { drink_id: number; qty: number };

const LONG_PRESS_MS = 450;
const PICKER_COUNTS = [1, 2, 3, 4, 5];

export function Sale({ config, onChangeBar }: Props) {
  const { bar, drinks } = config;
  const [lines, setLines] = useState<Line[]>([]);
  const [pfandReturns, setPfandReturns] = useState(0);
  const [submitting, setSubmitting] = useState(false);
  const [pickerDrink, setPickerDrink] = useState<Drink | null>(null);

  const longPressTimer = useRef<number | null>(null);
  const longPressFired = useRef(false);

  // One idempotency key per pending cart, reused across retries of the same
  // logical submission (e.g. after a timeout/dropped-connection error) so
  // the server's client_uuid dedup can actually recognise a resend. Reset
  // whenever the cart is cleared (submitted successfully or cancelled), so
  // the *next* cart gets its own fresh id.
  const cartUuidRef = useRef<string | null>(null);
  function cartUuid() {
    if (!cartUuidRef.current) cartUuidRef.current = uuid();
    return cartUuidRef.current;
  }

  const drinkById = useMemo(() => {
    const m = new Map<number, Drink>();
    drinks.forEach(d => m.set(d.id, d));
    return m;
  }, [drinks]);

  const total = useMemo(() => {
    const drinksSum = lines.reduce((sum, l) => {
      const d = drinkById.get(l.drink_id);
      if (!d) return sum;
      return sum + (d.price_cents + bar.pfand_cents) * l.qty;
    }, 0);
    return drinksSum - bar.pfand_cents * pfandReturns;
  }, [lines, drinkById, bar.pfand_cents, pfandReturns]);

  function addDrink(drinkId: number, qty = 1) {
    setLines(prev => {
      const i = prev.findIndex(l => l.drink_id === drinkId);
      if (i >= 0) {
        const copy = prev.slice();
        copy[i] = { ...copy[i]!, qty: copy[i]!.qty + qty };
        return copy;
      }
      return [...prev, { drink_id: drinkId, qty }];
    });
  }

  function incLine(drinkId: number, delta: number) {
    setLines(prev => {
      const i = prev.findIndex(l => l.drink_id === drinkId);
      if (i < 0) return prev;
      const nextQty = prev[i]!.qty + delta;
      if (nextQty <= 0) return prev.filter(l => l.drink_id !== drinkId);
      const copy = prev.slice();
      copy[i] = { ...copy[i]!, qty: nextQty };
      return copy;
    });
  }

  function addPfandReturn() {
    setPfandReturns(n => n + 1);
  }

  function incPfandReturns(delta: number) {
    setPfandReturns(n => Math.max(0, n + delta));
  }

  function clear() {
    setLines([]);
    setPfandReturns(0);
    cartUuidRef.current = null;
  }

  function startLongPress(d: Drink) {
    longPressFired.current = false;
    cancelLongPress();
    longPressTimer.current = window.setTimeout(() => {
      longPressFired.current = true;
      setPickerDrink(d);
    }, LONG_PRESS_MS);
  }

  function cancelLongPress() {
    if (longPressTimer.current != null) {
      clearTimeout(longPressTimer.current);
      longPressTimer.current = null;
    }
  }

  function handleDrinkClick(d: Drink) {
    // a long press already opened the count picker for this tap — swallow
    // the click that pointerup/click also fires, don't add a plain 1×.
    if (longPressFired.current) {
      longPressFired.current = false;
      return;
    }
    addDrink(d.id);
  }

  function pickCount(n: number) {
    if (pickerDrink) addDrink(pickerDrink.id, n);
    setPickerDrink(null);
  }

  const pfandCount = useMemo(() => lines.reduce((sum, l) => sum + l.qty, 0), [lines]);

  const isEmpty = lines.length === 0 && pfandReturns === 0;

  async function confirm(crew: boolean) {
    if (isEmpty || submitting) return;
    setSubmitting(true);
    const items: CartItem[] = lines.map(l => ({ drink_id: l.drink_id, qty: l.qty }));
    try {
      await api.createTransaction({
        client_uuid: cartUuid(),
        bar_id: bar.id,
        crew,
        items,
        pfand_returns: pfandReturns,
      });
      clear();
    } catch (e) {
      alert(`Fehler beim Speichern: ${e}`);
    } finally {
      setSubmitting(false);
    }
  }

  return (
    <div class="tablet">
      <div class="topbar">
        <div class="brand">
          <img class="logo" src="/favicon.svg" alt="" width="28" height="28" />
          <span class="bar-name">{bar.name}</span>
        </div>
        <button class="change" onClick={onChangeBar}>Bar wechseln</button>
      </div>

      <div class="grid">
        {drinks.map(d => (
          <button
            key={d.id}
            class="drink"
            onPointerDown={() => startLongPress(d)}
            onPointerUp={cancelLongPress}
            onPointerLeave={cancelLongPress}
            onPointerCancel={cancelLongPress}
            onContextMenu={e => e.preventDefault()}
            onClick={() => handleDrinkClick(d)}
          >
            <div class="name">{d.name}</div>
            <div class="price">{formatCents(d.price_cents)}</div>
            {bar.pfand_cents > 0 && (
              <div class="pfand">+ {formatCents(bar.pfand_cents)} Pfand</div>
            )}
          </button>
        ))}
        {bar.pfand_cents > 0 && (
          <button class="drink pfand-return" onClick={addPfandReturn}>
            <div class="name">Pfand zurück</div>
            <div class="price">−{formatCents(bar.pfand_cents)}</div>
          </button>
        )}
      </div>

      {pickerDrink && (
        <div class="picker-backdrop" onClick={() => setPickerDrink(null)}>
          <div class="picker" onClick={e => e.stopPropagation()}>
            <div class="picker-title">{pickerDrink.name}</div>
            <div class="picker-grid">
              {PICKER_COUNTS.map(n => (
                <button key={n} class="picker-count" onClick={() => pickCount(n)}>
                  {n}
                </button>
              ))}
            </div>
            <button class="picker-cancel" onClick={() => setPickerDrink(null)}>
              Abbrechen
            </button>
          </div>
        </div>
      )}

      <div class="cart">
        <div class="cart-items">
          <div class="cart-items-inner">
            {isEmpty && <div class="cart-line muted">Keine Einträge</div>}
            {lines.map((l, i) => {
              const d = drinkById.get(l.drink_id);
              if (!d) return null;
              return (
                <div key={i} class="cart-line">
                  <div class="cart-line-label">
                    <button class="qty-btn" onClick={() => incLine(l.drink_id, -1)} aria-label="weniger">
                      −
                    </button>
                    <span>{l.qty}× {d.name}</span>
                    <button class="qty-btn" onClick={() => incLine(l.drink_id, 1)} aria-label="mehr">
                      +
                    </button>
                  </div>
                  <span>{formatCents(d.price_cents * l.qty)}</span>
                </div>
              );
            })}
            {bar.pfand_cents > 0 && pfandCount > 0 && (
              <div class="cart-line pfand">
                <span>{pfandCount}× Pfand</span>
                <span>{formatCents(bar.pfand_cents * pfandCount)}</span>
              </div>
            )}
            {pfandReturns > 0 && (
              <div class="cart-line return">
                <div class="cart-line-label">
                  <button class="qty-btn" onClick={() => incPfandReturns(-1)} aria-label="weniger">
                    −
                  </button>
                  <span>{pfandReturns}× Pfand zurück</span>
                  <button class="qty-btn" onClick={() => incPfandReturns(1)} aria-label="mehr">
                    +
                  </button>
                </div>
                <span>{formatCents(-bar.pfand_cents * pfandReturns)}</span>
              </div>
            )}
          </div>
        </div>
        <div class={`cart-total ${total < 0 ? 'negative' : ''}`}>
          {formatCents(total)}
        </div>
        <div class="actions">
          <button class="cancel" onClick={clear} disabled={isEmpty || submitting}>
            Abbrechen
          </button>
          <button class="crew" onClick={() => confirm(true)} disabled={isEmpty || submitting}>
            Crew
          </button>
          <button class="confirm" onClick={() => confirm(false)} disabled={isEmpty || submitting}>
            Bestätigen
          </button>
        </div>
      </div>
    </div>
  );
}
