// App.jsx — root: estado, Supabase, persistencia local de respaldo, navegación, tweaks.
const { useState: useStateA, useEffect: useEffectA, useRef: useRefA } = React;

const STORE_KEY = "quiniela_mundial26_v3";
const ADMIN_PIN_KEY = "quiniela_admin_pin_session";
const QUINIELA_STATE_ID = "mundial_2026";

const SUPABASE_URL = "https://gdanpdhftjdwmkkpqica.supabase.co";
const SUPABASE_PUBLISHABLE_KEY = "sb_publishable_3a5E6lcp3Bl_jBcEai8_HQ_3prZjZH0";
const SUPABASE_CLIENT = window.supabase
  ? window.supabase.createClient(SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY)
  : null;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": ["#2433FF", "#0B1A8C"],
  "density": "regular",
  "ptExact": 5,
  "ptResult": 3
}/*EDITMODE-END*/;

function makeBaseState() {
  return {
    results: {},
    preds: JSON.parse(JSON.stringify(window.SEED_PREDS || {})),
    koWinners: {},
  };
}

function mergePreds(basePreds, savedPreds) {
  const out = JSON.parse(JSON.stringify(basePreds || {}));
  Object.keys(savedPreds || {}).forEach((mid) => {
    out[mid] = { ...(out[mid] || {}), ...(savedPreds[mid] || {}) };
  });
  return out;
}

function normalizeState(raw) {
  const base = makeBaseState();
  const s = raw || {};
  return {
    results: s.results || base.results,
    preds: mergePreds(base.preds, s.preds),
    koWinners: s.koWinners || s.ko_winners || base.koWinners,
    updatedAt: s.updatedAt || s.updated_at || null,
    updatedBy: s.updatedBy || s.updated_by || null,
  };
}

function normalizeRemoteState(row) {
  return normalizeState({
    results: row && row.results,
    preds: row && row.preds,
    ko_winners: row && row.ko_winners,
    updated_at: row && row.updated_at,
    updated_by: row && row.updated_by,
  });
}

function hasRemoteData(row) {
  if (!row) return false;
  return Object.keys(row.results || {}).length > 0 ||
    Object.keys(row.preds || {}).length > 0 ||
    Object.keys(row.ko_winners || {}).length > 0;
}

function loadState() {
  const base = makeBaseState();
  try {
    const raw = localStorage.getItem(STORE_KEY);
    if (raw) return normalizeState(JSON.parse(raw));
  } catch (e) {}
  return base;
}

const NAV = [
  { id: "tabla", label: "Tabla", icon: "table" },
  { id: "partidos", label: "Partidos", icon: "matches" },
  { id: "mundial", label: "Mundial", icon: "trophy" },
  { id: "reglas", label: "Reglas", icon: "info" },
];

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [state, setState] = useStateA(loadState);
  const [tab, setTab] = useStateA("tabla");
  const [activeMatch, setActiveMatch] = useStateA(null);
  const [menu, setMenu] = useStateA(false);
  const [adminPin, setAdminPin] = useStateA(() => {
    try { return sessionStorage.getItem(ADMIN_PIN_KEY) || ""; } catch (e) { return ""; }
  });
  const [syncStatus, setSyncStatus] = useStateA({
    kind: SUPABASE_CLIENT ? "loading" : "error",
    text: SUPABASE_CLIENT ? "Conectando con Supabase..." : "Supabase no cargó. Revisa la conexión."
  });
  const saveSeq = useRefA(0);
  const hydrateDone = useRefA(false);

  useEffectA(() => {
    try { localStorage.setItem(STORE_KEY, JSON.stringify({ ...state, updatedAt: new Date().toISOString() })); } catch (e) {}
  }, [state]);

  useEffectA(() => {
    const acc = Array.isArray(t.accent) ? t.accent : [t.accent, "#0B1A8C"];
    const root = document.documentElement;
    root.style.setProperty("--accent", acc[0]);
    root.style.setProperty("--accent-ink", acc[1] || "#0B1A8C");
  }, [t.accent]);

  const scoring = { exact: t.ptExact, result: t.ptResult };

  const formatSyncTime = () => {
    try {
      return new Intl.DateTimeFormat("es-VE", {
        timeZone: "America/Caracas",
        hour: "numeric",
        minute: "2-digit",
      }).format(new Date());
    } catch (e) {
      return "ahora";
    }
  };

  const ensureAdminPin = () => {
    const stored = adminPin || (() => {
      try { return sessionStorage.getItem(ADMIN_PIN_KEY) || ""; } catch (e) { return ""; }
    })();
    if (stored) return stored;

    const entered = window.prompt("Ingresa el PIN de administrador para guardar en Supabase:");
    if (!entered) {
      setSyncStatus({ kind: "warn", text: "Cambio cancelado: hace falta el PIN de administrador." });
      return null;
    }
    try { sessionStorage.setItem(ADMIN_PIN_KEY, entered); } catch (e) {}
    setAdminPin(entered);
    return entered;
  };

  const clearAdminPin = () => {
    try { sessionStorage.removeItem(ADMIN_PIN_KEY); } catch (e) {}
    setAdminPin("");
  };

  const saveRemote = async (nextState, pin) => {
    if (!SUPABASE_CLIENT) {
      setSyncStatus({ kind: "error", text: "No se pudo conectar con Supabase." });
      return false;
    }

    const seq = ++saveSeq.current;
    setSyncStatus({ kind: "loading", text: "Guardando en Supabase..." });

    const { data, error } = await SUPABASE_CLIENT.rpc("save_quiniela_state", {
      p_pin: pin,
      p_results: nextState.results || {},
      p_preds: nextState.preds || {},
      p_ko_winners: nextState.koWinners || {},
      p_updated_by: "app"
    });

    if (error) {
      if ((error.message || "").includes("invalid_pin")) {
        clearAdminPin();
        window.alert("PIN incorrecto. Vuelve a intentarlo.");
        setSyncStatus({ kind: "error", text: "No se guardó: PIN incorrecto." });
      } else {
        console.error(error);
        setSyncStatus({ kind: "error", text: "No se pudo guardar en Supabase. Revisa conexión o permisos." });
      }
      return false;
    }

    if (seq === saveSeq.current) {
      setSyncStatus({ kind: "ok", text: `Sincronizado · ${formatSyncTime()}` });
    }

    if (data) {
      const row = Array.isArray(data) ? data[0] : data;
      if (row && row.updated_at) {
        try {
          localStorage.setItem(STORE_KEY, JSON.stringify({
            ...nextState,
            updatedAt: row.updated_at,
            updatedBy: row.updated_by || "app"
          }));
        } catch (e) {}
      }
    }
    return true;
  };

  const fetchRemote = async ({ force = false } = {}) => {
    if (!SUPABASE_CLIENT) return;
    setSyncStatus({ kind: "loading", text: "Leyendo datos de Supabase..." });

    const { data, error } = await SUPABASE_CLIENT
      .from("quiniela_state")
      .select("id, results, preds, ko_winners, updated_at, updated_by")
      .eq("id", QUINIELA_STATE_ID)
      .single();

    if (error) {
      console.error(error);
      setSyncStatus({ kind: "error", text: "No se pudieron leer los datos de Supabase." });
      return;
    }

    if (force || hasRemoteData(data)) {
      setState(normalizeRemoteState(data));
      setSyncStatus({ kind: "ok", text: `Sincronizado · ${formatSyncTime()}` });
    } else {
      setSyncStatus({
        kind: "warn",
        text: "Supabase está vacío. Usa ‘Guardar este dispositivo en Supabase’ para subir los datos actuales."
      });
    }
    hydrateDone.current = true;
  };

  useEffectA(() => {
    if (!SUPABASE_CLIENT) return;

    let alive = true;
    let channel = null;

    const init = async () => {
      await fetchRemote();
      if (!alive) return;

      channel = SUPABASE_CLIENT
        .channel("quiniela_state_mundial_2026")
        .on("postgres_changes", {
          event: "UPDATE",
          schema: "public",
          table: "quiniela_state",
          filter: `id=eq.${QUINIELA_STATE_ID}`
        }, (payload) => {
          if (!payload || !payload.new) return;
          setState(normalizeRemoteState(payload.new));
          setSyncStatus({ kind: "ok", text: `Sincronizado · ${formatSyncTime()}` });
        })
        .subscribe();
    };

    init();

    return () => {
      alive = false;
      if (channel) SUPABASE_CLIENT.removeChannel(channel);
    };
  }, []);

  const updateStateWithAdmin = (updater) => {
    const pin = ensureAdminPin();
    if (!pin) return;

    setState((s) => {
      const next = typeof updater === "function" ? updater(s) : updater;
      saveRemote(next, pin);
      return next;
    });
  };

  const setResult = (mid, obj) => updateStateWithAdmin((s) => ({
    ...s,
    results: { ...s.results, [mid]: obj },
    // Si cambia un resultado de grupos, el cuadro y los ganadores manuales pueden dejar de coincidir.
    koWinners: {},
  }));

  const setPred = (mid, pid, side, val) => updateStateWithAdmin((s) => {
    const preds = { ...s.preds };
    preds[mid] = { ...(preds[mid] || {}) };
    preds[mid][pid] = { ...(preds[mid][pid] || {}), [side]: val };
    return { ...s, preds };
  });

  const setKoWinner = (key, side) => updateStateWithAdmin((s) => {
    let ko = { ...(s.koWinners || {}) };
    if (ko[key] === side) delete ko[key]; else ko[key] = side;
    // Limpia rondas posteriores que dependían de esta selección.
    ko = window.clearKoDependants ? window.clearKoDependants(ko, key) : ko;
    return { ...s, koWinners: ko };
  });

  const manualSave = async () => {
    const pin = ensureAdminPin();
    if (!pin) return;
    await saveRemote(state, pin);
    setMenu(false);
  };

  const manualLoad = async () => {
    await fetchRemote({ force: true });
    setMenu(false);
  };

  const askNewPin = () => {
    const entered = window.prompt("Ingresa el PIN de administrador:", "");
    if (!entered) {
      setMenu(false);
      return;
    }
    try { sessionStorage.setItem(ADMIN_PIN_KEY, entered); } catch (e) {}
    setAdminPin(entered);
    setSyncStatus({ kind: "ok", text: "Modo administrador activo en este dispositivo." });
    setMenu(false);
  };

  const resetData = () => {
    const pin = ensureAdminPin();
    if (!pin) return;
    if (!window.confirm("¿Seguro que quieres reiniciar la quiniela en Supabase y en este dispositivo?")) return;
    const fresh = { results: {}, preds: JSON.parse(JSON.stringify(window.SEED_PREDS || {})), koWinners: {} };
    try { localStorage.setItem(STORE_KEY, JSON.stringify(fresh)); } catch (e) {}
    setState(normalizeState(fresh));
    saveRemote(fresh, pin);
    setMenu(false);
  };

  return (
    <div className="app" data-density={t.density}>
      <div className="topbar">
        <div className="brand">
          <span className="brand-ball">26</span>
          <span className="brand-wm">QUINIELA<i>FAMILIAR</i></span>
        </div>
        <button className="kebab" onClick={() => setMenu((v) => !v)} aria-label="Menú">
          <span></span><span></span><span></span>
        </button>
        {menu && (
          <div className="menu-pop">
            <button onClick={askNewPin}>{adminPin ? "Cambiar PIN admin" : "Activar modo admin"}</button>
            <button onClick={manualSave}>Guardar este dispositivo en Supabase</button>
            <button onClick={manualLoad}>Recargar desde Supabase</button>
            <button onClick={resetData}>Reiniciar quiniela</button>
            <button onClick={() => setMenu(false)}>Cerrar</button>
          </div>
        )}
      </div>
      <window.StripeBar />
      {syncStatus && <div className={`syncbar ${syncStatus.kind}`}>{syncStatus.text}</div>}

      <main className="main">
        {tab === "tabla" && <window.StandingsScreen state={state} scoring={scoring} />}
        {tab === "partidos" && <window.MatchesScreen state={state} setPred={setPred} onOpen={setActiveMatch} />}
        {tab === "mundial" && <window.MundialScreen state={state} setKoWinner={setKoWinner} />}
        {tab === "reglas" && <window.RulesScreen scoring={scoring} />}
      </main>

      <nav className="bottomnav">
        {NAV.map((n) => (
          <button key={n.id} className={"nav-btn" + (tab === n.id ? " on" : "")}
            onClick={() => { setTab(n.id); setActiveMatch(null); }}>
            <window.Icon name={n.icon} size={22} />
            <span>{n.label}</span>
          </button>
        ))}
      </nav>


      {activeMatch && (
        <div className="detail-overlay">
          <window.MatchDetail matchId={activeMatch} state={state} scoring={scoring}
            setResult={setResult} setPred={setPred} onClose={() => setActiveMatch(null)} />
        </div>
      )}

      <TweaksPanel title="Tweaks">
        <TweakSection label="Estilo" />
        <TweakColor label="Color de acento" value={t.accent}
          options={[["#2433FF", "#0B1A8C"], ["#FF2E7E", "#9C0040"], ["#00B86B", "#06603B"], ["#E8113C", "#8C0A23"]]}
          onChange={(v) => setTweak("accent", v)} />
        <TweakRadio label="Densidad" value={t.density}
          options={["compact", "regular", "comfy"]}
          onChange={(v) => setTweak("density", v)} />
        <TweakSection label="Puntos por partido" />
        <TweakSlider label="Marcador exacto" value={t.ptExact} min={1} max={10}
          onChange={(v) => setTweak("ptExact", v)} />
        <TweakSlider label="Resultado correcto" value={t.ptResult} min={1} max={10}
          onChange={(v) => setTweak("ptResult", v)} />
      </TweaksPanel>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
