import { create } from 'zustand';
import type { FixturesFile, ModelSnapshot, ServerMessage, Snapshot } from '@/lib/types';
import { computeGroupTables } from '@/lib/standings';

export type ConnStatus = 'connecting' | 'live' | 'offline';

interface TournamentStore {
  snapshot: Snapshot | null;
  model: ModelSnapshot | null;
  status: ConnStatus;
  init: () => void;
}

let started = false;
let ws: WebSocket | null = null;
let retry = 0;

function wsUrl(): string {
  const proto = location.protocol === 'https:' ? 'wss' : 'ws';
  return `${proto}://${location.host}/ws`;
}

/** Last-resort fallback: build a seed snapshot straight from the static file
 *  (works on a plain static host with no server — degraded, no live updates). */
async function loadStaticSeed(): Promise<Snapshot | null> {
  try {
    const res = await fetch('/data/fixtures.json');
    if (!res.ok) return null;
    const file = (await res.json()) as FixturesFile;
    return {
      season: file.season,
      updatedAt: null,
      source: 'seed',
      fixtures: file.fixtures,
      tables: computeGroupTables(file.fixtures),
    };
  } catch {
    return null;
  }
}

export const useTournamentStore = create<TournamentStore>((set) => ({
  snapshot: null,
  model: null,
  status: 'connecting',

  init: () => {
    if (started) return;
    started = true;

    const connect = (): void => {
      try {
        ws = new WebSocket(wsUrl());
      } catch {
        set({ status: 'offline' });
        return;
      }
      ws.onmessage = (ev) => {
        try {
          const msg = JSON.parse(ev.data as string) as ServerMessage;
          if (msg.t === 'snapshot') set({ snapshot: msg.snapshot, status: 'live' });
          else if (msg.t === 'predictions') set({ model: msg.model });
        } catch { /* ignore malformed frame */ }
      };
      ws.onopen = () => { retry = 0; set({ status: 'live' }); };
      ws.onclose = () => {
        set({ status: 'offline' });
        retry = Math.min(retry + 1, 6);
        setTimeout(connect, 1000 * 2 ** retry); // capped exponential backoff
      };
      ws.onerror = () => { try { ws?.close(); } catch { /* noop */ } };
    };

    // Initial paint from REST (fast), then the WS takes over for live updates.
    void (async () => {
      try {
        const [snap, preds] = await Promise.all([fetch('/api/snapshot'), fetch('/api/predictions')]);
        if (snap.ok) set({ snapshot: (await snap.json()) as Snapshot });
        if (preds.ok) set({ model: (await preds.json()) as ModelSnapshot });
      } catch { /* server may be absent on a static host */ }
      if (!useTournamentStore.getState().snapshot) {
        const seed = await loadStaticSeed();
        if (seed) set({ snapshot: seed, status: 'offline' });
      }
      connect();
    })();
  },
}));
