/* store.jsx — prediction state + Supabase persistence.
   Each visitor gets a UUID stored in localStorage.
   Predictions are upserted to the `predictions` table on every change (debounced).
   Loading /bworldcuppredictor?p=<uuid> fetches that row read-only.
   window.useStore */
(function () {
  const LOCAL_KEY = 'bwcp:v2';
  const UUID_KEY  = 'bwcp:uuid';

  /* ---------- Supabase client singleton ---------- */
  function getSB() {
    if (window._bwcpSB) return window._bwcpSB;
    const cfg = window.BWCP_CONFIG;
    if (!cfg || !window.supabase) return null;
    window._bwcpSB = window.supabase.createClient(cfg.supabaseUrl, cfg.supabaseAnonKey);
    return window._bwcpSB;
  }

  /* ---------- UUID ---------- */
  function getOrCreateUUID() {
    let id = localStorage.getItem(UUID_KEY);
    if (!id) {
      id = crypto.randomUUID
        ? crypto.randomUUID()
        : 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
            const r = Math.random() * 16 | 0;
            return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
          });
      localStorage.setItem(UUID_KEY, id);
    }
    return id;
  }

  /* ---------- local helpers ---------- */
  const blank = () => ({ results: {}, ko: {}, name: '', quiz_log: {}, email: '' });

  function loadLocal() {
    try {
      const raw = localStorage.getItem(LOCAL_KEY);
      if (raw) return { ...blank(), ...JSON.parse(raw) };
    } catch (_) {}
    // First ever visit — seed favourites so every screen looks alive
    const results = window.WCLogic.defaultPredictions();
    return { results, ko: window.WCLogic.defaultKO(results), name: '', quiz_log: {}, email: '' };
  }

  /* ---------- debounce ---------- */
  function debounce(fn, ms) {
    let t;
    return (...args) => { clearTimeout(t); t = setTimeout(() => fn(...args), ms); };
  }

  /* ---------- Supabase ops ---------- */
  async function upsert(uuid, state) {
    const sb = getSB();
    if (!sb) return;
    const payload = { id: uuid, name: state.name || null, results: state.results, ko: state.ko, quiz_log: state.quiz_log || {}, updated_at: new Date().toISOString() };
    // Only include email when set, so an empty local value never clobbers an
    // address already saved via a different screen (Summary vs. Quiz gate).
    if (state.email) payload.email = state.email;
    await sb.from('predictions').upsert(payload, { onConflict: 'id' });
  }

  /* Entering an email already attached to another row "claims" it: merge
     this device's local progress into that row (keep whichever results/ko
     scores higher vs real_scores, union quiz_log) and drop this row.
     Returns { claimed, id, results?, ko?, quiz_log?, name? }. */
  async function claimByEmail(uuid, email, state) {
    const sb = getSB();
    if (!sb) return null;
    const { data, error } = await sb.rpc('claim_prediction_by_email', {
      p_uuid: uuid,
      p_email: email,
      p_local: { results: state.results, ko: state.ko, quiz_log: state.quiz_log || {}, name: state.name || '' },
    });
    if (error) { console.error(error); return null; }
    return data;
  }

  async function fetchById(uuid) {
    const sb = getSB();
    if (!sb) return null;
    const { data, error } = await sb.from('predictions').select('*').eq('id', uuid).single();
    if (error || !data) return null;
    return { results: data.results || {}, ko: data.ko || {}, name: data.name || '', quiz_log: data.quiz_log || {}, email: data.email || '' };
  }

  /* ---------- hook ---------- */
  function useStore() {
    const { useState, useEffect, useCallback, useRef } = React;
    const [uuid, setUuid] = useState(getOrCreateUUID);
    const [state, setState] = useState(loadLocal);
    const isSharedRef = useRef(false);

    /* On mount: check ?p=uuid — if present, load that prediction read-only */
    useEffect(() => {
      // Tie Amplitude identity to prediction UUID
      window.bwcpIdentify?.(uuid);

      const params = new URLSearchParams(location.search);
      const sharedId = params.get('p');
      if (sharedId && sharedId !== uuid) {
        isSharedRef.current = true;
        fetchById(sharedId).then(data => { if (data) setState(data); });
      } else {
        // Own prediction — ensure the row exists in Supabase
        upsert(uuid, state);
        // Backfill: pre-quiz-gate visitors may already have given their email
        // via the Summary screen, but it never made it into local state.
        if (!state.email) {
          fetchById(uuid).then(data => {
            if (data?.email) setState(s => ({ ...s, email: data.email }));
          });
        }
      }
    }, []); // eslint-disable-line react-hooks/exhaustive-deps

    /* Persist locally */
    useEffect(() => {
      if (isSharedRef.current) return;
      try { localStorage.setItem(LOCAL_KEY, JSON.stringify(state)); } catch (_) {}
    }, [state]);

    /* Debounced Supabase sync (750 ms after last change) */
    const debouncedUpsert = useRef(debounce((u, s) => upsert(u, s), 750));
    useEffect(() => {
      if (isSharedRef.current) return;
      debouncedUpsert.current(uuid, state);
    }, [state, uuid]);

    /* ---- mutation helpers ---- */
    const setResult = useCallback((id, partial) => setState(s => {
      const next = { ...(s.results[id] || {}), ...partial };
      return { ...s, results: { ...s.results, [id]: next } };
    }), []);

    const pickWinner = useCallback((key, code) => setState(s => ({
      ...s, ko: { ...s.ko, [key]: code },
    })), []);

    const fillFavourites = useCallback(() => {
      window.bwcpTrack?.('bwcp_fill_favourites');
      setState(s => {
        const results = window.WCLogic.defaultPredictions();
        return { results, ko: window.WCLogic.defaultKO(results), name: '', quiz_log: s.quiz_log };
      });
    }, []);

    const autoKO = useCallback(() => setState(s => ({
      ...s, ko: window.WCLogic.defaultKO(s.results),
    })), []);

    const reset = useCallback(() => {
      window.bwcpTrack?.('bwcp_reset');
      setState(blank());
    }, []);

    const setName = useCallback(name => setState(s => ({ ...s, name })), []);

    /* Record one quiz answer. key = `${teamCode}-${md}`, idx = question index,
       correct = whether the chosen choice was right. Idempotent per (key, idx). */
    const setQuizAnswer = useCallback((key, idx, correct) => setState(s => ({
      ...s,
      quiz_log: { ...s.quiz_log, [key]: { ...(s.quiz_log[key] || {}), [idx]: correct } },
    })), []);

    /* Save + remember the visitor's email so gates (Quiz) don't re-prompt.
       If this email is already attached to another row, claim it instead —
       merge this device's progress in and continue under that row's id. */
    const setEmail = useCallback(async (email) => {
      const res = await claimByEmail(uuid, email, state);
      if (res?.claimed) {
        localStorage.setItem(UUID_KEY, res.id);
        setUuid(res.id);
        window.bwcpIdentify?.(res.id);
        setState(s => ({
          ...s,
          results: res.results || s.results,
          ko: res.ko || s.ko,
          quiz_log: res.quiz_log || s.quiz_log,
          name: res.name || s.name,
          email,
        }));
      } else {
        setState(s => ({ ...s, email }));
      }
    }, [uuid, state]);

    return {
      state, uuid,
      isShared: isSharedRef.current,
      setResult, pickWinner, fillFavourites, autoKO, reset, setName, setQuizAnswer,
      saveEmail: setEmail,
    };
  }

  window.useStore = useStore;
})();
