/* ── Stien — Kraamkost meal-train calendar ─────────────────────────────────
   People sign up for a day to bring a meal; booking a day locks the slot.
   Three layouts, switchable via the `variant` tweak: maand · lijst · week.

   Storage: shared via Supabase when window.STIEN_SUPABASE is filled in,
   otherwise local-only (per browser) as a fallback so the page always works.

   Ownership without logins ("claim token"): each booking gets a random secret
   stored in THIS browser + a hash of it stored on the row. So only the person
   who booked a day sees the wijzig/annuleer controls; everyone else just sees
   it as taken. See supabase-setup.sql for the table + functions.            */

const KK_GIFT     = "kraamkost";
const KK_WD_SHORT = ["ma", "di", "wo", "do", "vr", "za", "zo"];
const KK_WD_LONG  = ["maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag", "zondag"];
const KK_MONTHS   = ["januari", "februari", "maart", "april", "mei", "juni",
                     "juli", "augustus", "september", "oktober", "november", "december"];

function kkParse(iso) { const [y, m, d] = iso.split("-").map(Number); return new Date(y, m - 1, d); }
function kkMonIdx(d) { return (d.getDay() + 6) % 7; }                 // monday-based weekday index
function kkIso(y, m, d) { return `${y}-${String(m + 1).padStart(2, "0")}-${String(d).padStart(2, "0")}`; }
function kkLong(iso) { const d = kkParse(iso); return `${KK_WD_LONG[kkMonIdx(d)]} ${d.getDate()} ${KK_MONTHS[d.getMonth()]}`; }
function kkBrusselsNow() {
  const parts = new Intl.DateTimeFormat("en-CA", {
    timeZone: "Europe/Brussels",
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
    hour: "2-digit",
    hourCycle: "h23",
  }).formatToParts(new Date()).reduce((m, p) => ((m[p.type] = p.value), m), {});
  return { iso: `${parts.year}-${parts.month}-${parts.day}`, hour: Number(parts.hour) };
}
function kkTodayIso() {
  if (window.STIEN_TODAY) return window.STIEN_TODAY;
  return kkBrusselsNow().iso;
}
function kkIsPast(iso) {
  const today = kkTodayIso();
  if (iso < today) return true;
  if (iso > today) return false;
  if (window.STIEN_TODAY) return false;
  return kkBrusselsNow().hour >= 12;
}
function kkRangeSlots(start, end) {
  if (!start || !end) return [];
  const out = [];
  for (let d = kkParse(start), last = kkParse(end); d <= last; d.setDate(d.getDate() + 1)) {
    out.push(kkIso(d.getFullYear(), d.getMonth(), d.getDate()));
  }
  return out;
}
function kkGiftSlots(gift) {
  return gift.slots || kkRangeSlots(gift.slotStart, gift.slotEnd);
}

function kkToken() {
  if (window.crypto && crypto.randomUUID) return crypto.randomUUID();
  return Math.random().toString(36).slice(2) + Date.now().toString(36);
}

/* Supabase client (created once, only when configured). */
function kkSupabase() {
  const cfg = window.STIEN_SUPABASE || {};
  if (!cfg.url || !cfg.anonKey || !window.supabase) return null;
  if (!kkSupabase._c) kkSupabase._c = window.supabase.createClient(cfg.url, cfg.anonKey);
  return kkSupabase._c;
}

/* ── booking state hook ──
   Returns { map, mine, online, loaded, book, rename, release, refetch }.
   · map    { "YYYY-MM-DD": "Naam" }   — every booked day
   · mine   { "YYYY-MM-DD": token }    — days this browser can edit/cancel  */
function useBookings(seed) {
  const LOCAL_KEY = "stien_kraam_v2";
  const TOKEN_KEY = "stien_kraam_tokens_v2";
  const sb = kkSupabase();

  const loadTokens = () => { try { return JSON.parse(localStorage.getItem(TOKEN_KEY) || "{}"); } catch (e) { return {}; } };
  const [map, setMap] = React.useState({});
  const [tokens, setTokens] = React.useState(loadTokens);
  const [loaded, setLoaded] = React.useState(false);

  const saveTokens = (t) => localStorage.setItem(TOKEN_KEY, JSON.stringify(t));
  const persistLocal = (m) => localStorage.setItem(LOCAL_KEY, JSON.stringify(m));

  const refetch = React.useCallback(async () => {
    if (!sb) return;
    const { data } = await sb.from("bookings").select("slot,name").eq("gift_id", KK_GIFT);
    const m = {}; (data || []).forEach((r) => { m[r.slot] = r.name; });
    setMap(m);
  }, [sb]);

  React.useEffect(() => {
    let alive = true;
    if (sb) {
      sb.from("bookings").select("slot,name").eq("gift_id", KK_GIFT).then(({ data }) => {
        if (!alive) return;
        const m = {}; (data || []).forEach((r) => { m[r.slot] = r.name; });
        setMap(m); setLoaded(true);
      });
    } else {
      let stored = null;
      try { stored = JSON.parse(localStorage.getItem(LOCAL_KEY) || "null"); } catch (e) {}
      setMap(stored || { ...(seed || {}) });
      setLoaded(true);
    }
    return () => { alive = false; };
  }, [sb]);

  const book = async (slot, name) => {
    const token = kkToken();
    if (sb) {
      const { data, error } = await sb.rpc("book_slot",
        { p_gift: KK_GIFT, p_slot: slot, p_name: name, p_token: token });
      if (error || !data || data.length === 0) { await refetch(); return false; }
    }
    setMap((p) => { const n = { ...p, [slot]: name }; if (!sb) persistLocal(n); return n; });
    setTokens((p) => { const t = { ...p, [slot]: token }; saveTokens(t); return t; });
    if (sb && window.kkNotifyBooking) window.kkNotifyBooking(slot, name, kkLong(slot), token);
    return true;
  };

  const rename = async (slot, name) => {
    const token = tokens[slot];
    if (sb) {
      if (!token) return false;
      const { data } = await sb.rpc("rename_slot",
        { p_gift: KK_GIFT, p_slot: slot, p_name: name, p_token: token });
      if (data !== true) { await refetch(); return false; }
    }
    setMap((p) => { const n = { ...p, [slot]: name }; if (!sb) persistLocal(n); return n; });
    return true;
  };

  const release = async (slot) => {
    const token = tokens[slot];
    if (sb) {
      if (!token) return false;
      const { data } = await sb.rpc("cancel_slot",
        { p_gift: KK_GIFT, p_slot: slot, p_token: token });
      if (data !== true) { await refetch(); return false; }
    }
    setMap((p) => { const n = { ...p }; delete n[slot]; if (!sb) persistLocal(n); return n; });
    setTokens((p) => { const t = { ...p }; delete t[slot]; saveTokens(t); return t; });
    return true;
  };

  return { map, mine: tokens, online: !!sb, loaded, book, rename, release, refetch };
}

function KraamCalendar({ slots, bookings, mine, onBook, onRename, onRelease, variant }) {
  const locked = bookings.locked || {};
  const booked = bookings.booked || bookings;
  const expired = slots.reduce((m, iso) => (kkIsPast(iso) && !locked[iso] ? { ...m, [iso]: "voorbij" } : m), {});
  const todayIso = kkTodayIso();
  const [selected, setSelected] = React.useState(null);  // free day → booking form
  const [manage, setManage] = React.useState(null);      // my day → manage form
  const [releasing, setReleasing] = React.useState(null);// confirm cancel
  const [help, setHelp] = React.useState(null);          // taken day without local claim token
  const [name, setName] = React.useState("");
  const [editName, setEditName] = React.useState("");
  const [error, setError] = React.useState("");

  const reset = () => { setSelected(null); setManage(null); setReleasing(null); setHelp(null); setError(""); };
  const pick = (iso) => { if (locked[iso] || expired[iso]) return; reset(); setSelected(iso); setName(""); };
  const openManage = (iso) => { if (locked[iso] || expired[iso]) return; reset(); setManage(iso); setEditName(booked[iso] || ""); };
  const showHelp = (iso) => { if (locked[iso] || expired[iso]) return; reset(); setHelp(iso); };

  const confirmBook = async () => {
    if (!name.trim()) return;
    const ok = await onBook(selected, name.trim());
    if (!ok) { setError("Deze dag kon niet worden vastgezet. Probeer opnieuw."); return; }
    setSelected(null); setName("");
  };
  const saveName = async () => {
    if (!editName.trim()) return;
    const ok = await onRename(manage, editName.trim());
    if (!ok) { setError("Deze naam kon niet worden aangepast. Probeer opnieuw."); return; }
    setManage(null);
  };
  const confirmRelease = async () => {
    const ok = await onRelease(releasing);
    if (!ok) { setError("Deze dag kon niet worden vrijgegeven. Probeer opnieuw."); return; }
    setReleasing(null);
  };

  React.useEffect(() => {
    if (variant === "maand" || !slots.includes(todayIso)) return;
    const el = document.querySelector(`[data-kk-date="${todayIso}"]`);
    if (el) el.scrollIntoView({ block: "center", inline: "center" });
  }, [slots, todayIso, variant]);

  const view = { slots, bookings: booked, locked, expired, mine, todayIso, selected, manage, releasing, help, onPick: pick, onManage: openManage, onHelp: showHelp };

  return (
    <div className="kk">
      {variant === "maand" ? <MonthGrid {...view} />
        : variant === "week" ? <WeekChips {...view} />
        : <DayList {...view} />}

      {selected && !locked[selected] && !expired[selected] && !booked[selected] && (
        <div className="kk-form">
          <p>Je brengt eten langs op <b>{kkLong(selected)}</b>.</p>
          <input className="kk-input" placeholder="je naam" value={name} autoFocus
            onChange={(e) => setName(e.target.value)}
            onKeyDown={(e) => e.key === "Enter" && confirmBook()} />
          <div className="kk-form-row">
            <button className="rc-no" onClick={() => setSelected(null)}>Annuleer</button>
            <button className="rc-yes" disabled={!name.trim()} onClick={confirmBook}>Zet me vast</button>
          </div>
          {error && <p className="kk-error">{error}</p>}
        </div>
      )}

      {manage && (
        <div className="kk-form">
          <p>Jouw dag — <b>{kkLong(manage)}</b>. Pas je naam aan of geef de dag weer vrij.</p>
          <input className="kk-input" placeholder="je naam" value={editName} autoFocus
            onChange={(e) => setEditName(e.target.value)}
            onKeyDown={(e) => e.key === "Enter" && saveName()} />
          <div className="kk-form-row">
            <button className="rc-no" onClick={() => setManage(null)}>Sluiten</button>
            <button className="rc-yes" disabled={!editName.trim()} onClick={saveName}>Bewaar</button>
          </div>
          <button className="kk-rel kk-rel-block" onClick={() => { setManage(null); setReleasing(manage); }}>
            deze dag vrijgeven
          </button>
          {error && <p className="kk-error">{error}</p>}
        </div>
      )}

      {releasing && (
        <div className="kk-form">
          <p><b>{kkLong(releasing)}</b> komt weer vrij voor iemand anders. Zeker?</p>
          <div className="kk-form-row">
            <button className="rc-no" onClick={() => setReleasing(null)}>Laat staan</button>
            <button className="rc-yes" onClick={confirmRelease}>Ja, vrijgeven</button>
          </div>
          {error && <p className="kk-error">{error}</p>}
        </div>
      )}

      {help && (
        <p className="kk-help">Dag aanpassen en geen wijzig-knop? Mail Bram: <a href="mailto:bram.van.rompuy@gmail.com">bram.van.rompuy@gmail.com</a></p>
      )}
    </div>
  );
}

/* ── lijst: dates stacked, clearest on mobile ── */
function DayList({ slots, bookings, locked, expired, mine, todayIso, selected, manage, releasing, help, onPick, onManage, onHelp }) {
  return (
    <div className="kk-list">
      {slots.map((iso) => {
        const d = kkParse(iso);
        const lockedLabel = locked[iso];
        const expiredLabel = expired[iso];
        const taken = lockedLabel || expiredLabel || bookings[iso];
        const isMine = !lockedLabel && !expiredLabel && !!mine[iso];
        const isToday = iso === todayIso;
        const active = selected === iso || manage === iso || releasing === iso || help === iso;
        const cls = "kk-row"
          + (taken ? " is-taken" : "")
          + (lockedLabel ? " is-locked" : "")
          + (expiredLabel ? " is-expired" : "")
          + (isMine ? " is-mine" : "")
          + (isToday ? " is-today" : "")
          + (active ? " is-active" : "");
        return (
          <div key={iso} className={cls} data-kk-date={iso}>
            <div className="kk-date">
              <span className="kk-day">{d.getDate()}</span>
              <span className="kk-mon">{KK_MONTHS[d.getMonth()].slice(0, 3)}</span>
            </div>
            <div className="kk-meta">
              <span className="kk-wd">{KK_WD_LONG[kkMonIdx(d)]}</span>
              {lockedLabel ? <span className="kk-by">{lockedLabel}</span>
                     : expiredLabel ? <span className="kk-by">{expiredLabel}</span>
                     : taken ? <span className="kk-by">{isMine ? "jij brengt eten" : taken + " brengt eten"}</span>
                     : <span className="kk-free">nog vrij</span>}
            </div>
            {lockedLabel ? <span className="kk-lock">bezet</span>
              : expiredLabel ? <span className="kk-lock">voorbij</span>
              : taken
              ? (isMine ? <button className="kk-rel" onClick={() => onManage(iso)}>wijzig</button>
                        : <button className="kk-rel" onClick={() => onHelp(iso)}>genomen</button>)
              : <button className="kk-pick" onClick={() => onPick(iso)}>kies</button>}
          </div>
        );
      })}
    </div>
  );
}

/* ── maand: month grid, available days lit, taken days filled ── */
function MonthGrid({ slots, bookings, locked, expired, mine, todayIso, selected, manage, releasing, help, onPick, onManage, onHelp }) {
  const monthGroups = [...slots].sort().reduce((groups, iso) => {
    const d = kkParse(iso);
    const key = `${d.getFullYear()}-${d.getMonth()}`;
    let group = groups.find((g) => g.key === key);
    if (!group) {
      group = { key, year: d.getFullYear(), month: d.getMonth(), slots: [] };
      groups.push(group);
    }
    group.slots.push(iso);
    return groups;
  }, []);
  const todayMonthIndex = monthGroups.findIndex((g) => g.slots.includes(todayIso));
  const [monthIndex, setMonthIndex] = React.useState(() => Math.max(0, todayMonthIndex));

  if (monthGroups.length === 0) {
    return <div className="kk-cal"><div className="kk-cal-cap">geen dagen ingesteld</div></div>;
  }

  const activeGroup = monthGroups[Math.min(monthIndex, monthGroups.length - 1)];
  const renderMonth = ({ key, year, month, slots: monthSlots }) => {
    const offset = kkMonIdx(new Date(year, month, 1));
    const daysIn = new Date(year, month + 1, 0).getDate();
    const slotSet = new Set(monthSlots);

    const cells = [];
    for (let i = 0; i < offset; i++) cells.push(<span key={"b" + i} className="kk-cell is-blank" />);
    for (let day = 1; day <= daysIn; day++) {
      const iso = kkIso(year, month, day);
      const avail = slotSet.has(iso);
      const lockedLabel = locked[iso];
      const expiredLabel = expired[iso];
      const taken = lockedLabel || expiredLabel || bookings[iso];
      const isMine = !lockedLabel && !expiredLabel && !!mine[iso];
      const isToday = iso === todayIso;
      const active = selected === iso || manage === iso || releasing === iso || help === iso;
      const interactive = avail && !lockedLabel && !expiredLabel;
      const cls = "kk-cell"
        + (!avail ? " is-off" : "")
        + (taken && !isMine ? " is-taken" : "")
        + (lockedLabel ? " is-locked" : "")
        + (expiredLabel ? " is-expired" : "")
        + (isMine ? " is-mine" : "")
        + (isToday ? " is-today" : "")
        + (active ? " is-active" : "");
      cells.push(
        <button key={iso} className={cls} disabled={!interactive} title={taken || ""}
          data-kk-date={iso}
          onClick={interactive ? () => (taken ? (isMine ? onManage(iso) : onHelp(iso)) : onPick(iso)) : undefined}>
          {day}
          {taken && <i className="kk-cell-dot" />}
        </button>
      );
    }

    return (
      <div className="kk-cal" key={key}>
        <div className="kk-cal-h">{KK_WD_SHORT.map((w) => <span key={w}>{w}</span>)}</div>
        <div className="kk-cal-g">{cells}</div>
      </div>
    );
  };

  return (
    <div className="kk-months">
      <div className="kk-cal-nav">
        <button className="kk-cal-arrow" type="button" aria-label="Vorige maand"
          disabled={monthIndex === 0}
          onClick={() => setMonthIndex((i) => Math.max(0, i - 1))}>‹</button>
        <div className="kk-cal-cap">{KK_MONTHS[activeGroup.month]} {activeGroup.year}</div>
        <button className="kk-cal-arrow" type="button" aria-label="Volgende maand"
          disabled={monthIndex === monthGroups.length - 1}
          onClick={() => setMonthIndex((i) => Math.min(monthGroups.length - 1, i + 1))}>›</button>
      </div>
      {renderMonth(activeGroup)}
    </div>
  );
}

/* ── week: days as chips ── */
function WeekChips({ slots, bookings, locked, expired, mine, todayIso, selected, manage, releasing, help, onPick, onManage, onHelp }) {
  return (
    <div className="kk-chips">
      {slots.map((iso) => {
        const d = kkParse(iso);
        const lockedLabel = locked[iso];
        const expiredLabel = expired[iso];
        const taken = lockedLabel || expiredLabel || bookings[iso];
        const isMine = !lockedLabel && !expiredLabel && !!mine[iso];
        const isToday = iso === todayIso;
        const active = selected === iso || manage === iso || releasing === iso || help === iso;
        const interactive = !lockedLabel && !expiredLabel;
        return (
          <button key={iso} title={taken || ""} disabled={!interactive}
            className={"kk-chip" + (taken && !isMine ? " is-taken" : "") + (lockedLabel ? " is-locked" : "") + (expiredLabel ? " is-expired" : "") + (isMine ? " is-mine" : "") + (isToday ? " is-today" : "") + (active ? " is-active" : "")}
            data-kk-date={iso}
            onClick={interactive ? () => (taken ? (isMine ? onManage(iso) : onHelp(iso)) : onPick(iso)) : undefined}>
            <span className="kk-chip-wd">{KK_WD_SHORT[kkMonIdx(d)]}</span>
            <span className="kk-chip-d">{d.getDate()}</span>
            <span className="kk-chip-st">{lockedLabel ? "bezet" : expiredLabel ? "voorbij" : taken ? (isMine ? "jij" : "genomen") : "vrij"}</span>
          </button>
        );
      })}
    </div>
  );
}

Object.assign(window, { useBookings, KraamCalendar, kkLong, kkGiftSlots });
