// store.jsx — Global state, persistence, sample data, import/export
const { createContext, useContext, useState, useEffect, useMemo, useCallback, useRef } = React;

const STORAGE_KEY = "soccer_sub_planner_v1";

const DEFAULT_POSITION_LABELS = {
  1: "GK",
  2: "RB",
  3: "CB",
  4: "CB",
  5: "LB",
  6: "CM",
  7: "RW",
  8: "CM",
  9: "ST",
  10: "CAM",
  11: "LW",
};

// Approximate pitch positions for an 11-pos diagram (x, y in % of pitch)
const POSITION_COORDS = {
  1:  { x: 50, y: 92 },
  4:  { x: 32, y: 75 },
  5:  { x: 68, y: 75 },
  2:  { x: 85, y: 68 },
  3:  { x: 15, y: 68 },
  6:  { x: 50, y: 62 },
  8:  { x: 35, y: 48 },
  10: { x: 65, y: 48 },
  7:  { x: 82, y: 32 },
  11: { x: 18, y: 32 },
  9:  { x: 50, y: 18 },
};

function uid() {
  return Math.random().toString(36).slice(2, 10);
}

function buildDefaultState() {
  return {
    match: {
      homeTeam: "KFCH Sinaai",
      awayTeam: "",
      isUserHomeTeam: true,
      periods: 4,
      periodMinutes: 20,
      location: "",
    },
    players: [],
    formation: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
    positionLabels: { ...DEFAULT_POSITION_LABELS },
    // gamePlan[periodIndex][halfIndex][positionNumber] = playerId
    gamePlan: {},
    // Team aandachtspunten
    teamFocus: {
      ballPlus: ["", ""],   // B+ (balbezit)
      ballMinus: ["", ""],  // B- (balverlies)
    },
    // Per-speler werkpunten: { playerId: "..." }
    playerNotes: {},
    activeTab: "setup",
  };
}

const SAMPLE_NAMES = [
  "Alex Rivera", "Sam Okafor", "Jordan Kim", "Noah Patel",
  "Marco Silva", "Theo Lange", "Ben Carter", "Luca Romano",
  "Ezra Hayes", "Finn Walsh", "Kai Nakamura", "Owen Brooks",
  "Mateo Cruz", "Jude Ellis",
];

function buildSampleState() {
  return {
    ...buildDefaultState(),
    match: {
      homeTeam: "Lions FC",
      awayTeam: "Northside United",
      isUserHomeTeam: true,
      periods: 4,
      periodMinutes: 20,
    },
    players: SAMPLE_NAMES.map((name) => ({ id: uid(), name })),
    activeTab: "planner",
  };
}

function loadState() {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (!raw) return buildDefaultState();
    const parsed = JSON.parse(raw);
    return { ...buildDefaultState(), ...parsed };
  } catch (e) {
    console.warn("Failed to load state, using defaults", e);
    return buildDefaultState();
  }
}

const StoreContext = createContext(null);

function StoreProvider({ children }) {
  const [state, setState] = useState(loadState);

  // Persist on every change
  useEffect(() => {
    try {
      localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
    } catch (e) {
      console.warn("Persist failed", e);
    }
  }, [state]);

  const update = useCallback((updater) => {
    setState((prev) => {
      const next = typeof updater === "function" ? updater(prev) : { ...prev, ...updater };
      return next;
    });
  }, []);

  // ----- Match -----
  const setMatch = useCallback((patch) => {
    update((prev) => ({ ...prev, match: { ...prev.match, ...patch } }));
  }, [update]);

  // ----- Players -----
  const addPlayer = useCallback((name) => {
    update((prev) => ({
      ...prev,
      players: [...prev.players, { id: uid(), name: name || `Player ${prev.players.length + 1}` }],
    }));
  }, [update]);

  const updatePlayer = useCallback((id, name) => {
    update((prev) => ({
      ...prev,
      players: prev.players.map((p) => (p.id === id ? { ...p, name } : p)),
    }));
  }, [update]);

  const removePlayer = useCallback((id) => {
    update((prev) => {
      // also strip from gamePlan
      const gp = JSON.parse(JSON.stringify(prev.gamePlan || {}));
      for (const pIdx of Object.keys(gp)) {
        for (const hIdx of Object.keys(gp[pIdx])) {
          for (const pos of Object.keys(gp[pIdx][hIdx])) {
            if (gp[pIdx][hIdx][pos] === id) delete gp[pIdx][hIdx][pos];
          }
        }
      }
      return {
        ...prev,
        players: prev.players.filter((p) => p.id !== id),
        gamePlan: gp,
      };
    });
  }, [update]);

  // ----- Formation -----
  const togglePosition = useCallback((pos) => {
    update((prev) => {
      const set = new Set(prev.formation);
      if (set.has(pos)) set.delete(pos);
      else set.add(pos);
      return { ...prev, formation: [...set].sort((a, b) => a - b) };
    });
  }, [update]);

  const setFormation = useCallback((arr) => {
    update((prev) => ({ ...prev, formation: [...arr].sort((a, b) => a - b) }));
  }, [update]);

  const setPositionLabel = useCallback((pos, label) => {
    update((prev) => ({
      ...prev,
      positionLabels: { ...prev.positionLabels, [pos]: label },
    }));
  }, [update]);

  const setTeamFocus = useCallback((kind, index, value) => {
    update((prev) => {
      const arr = [...(prev.teamFocus?.[kind] || ["", ""])];
      arr[index] = value;
      return { ...prev, teamFocus: { ...prev.teamFocus, [kind]: arr } };
    });
  }, [update]);

  const setPlayerNote = useCallback((pid, note) => {
    update((prev) => {
      const next = { ...(prev.playerNotes || {}) };
      if (note) next[pid] = note;
      else delete next[pid];
      return { ...prev, playerNotes: next };
    });
  }, [update]);

  // ----- Game Plan -----
  const assignPlayer = useCallback((periodIdx, halfIdx, position, playerId) => {
    update((prev) => {
      const gp = JSON.parse(JSON.stringify(prev.gamePlan || {}));
      gp[periodIdx] = gp[periodIdx] || {};
      gp[periodIdx][halfIdx] = gp[periodIdx][halfIdx] || {};
      if (playerId == null) {
        delete gp[periodIdx][halfIdx][position];
      } else {
        // Prevent assigning same player to another position in the SAME half-period
        const cell = gp[periodIdx][halfIdx];
        for (const pos of Object.keys(cell)) {
          if (cell[pos] === playerId) delete cell[pos];
        }
        cell[position] = playerId;
      }
      return { ...prev, gamePlan: gp };
    });
  }, [update]);

  const clearAssignments = useCallback(() => {
    update((prev) => ({ ...prev, gamePlan: {} }));
  }, [update]);

  const setActiveTab = useCallback((tab) => {
    update({ activeTab: tab });
  }, [update]);

  // ----- Import / Export -----
  const exportJSON = useCallback(() => {
    const blob = new Blob([JSON.stringify(state, null, 2)], { type: "application/json" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    const stamp = new Date().toISOString().slice(0, 16).replace(/[:T]/g, "-");
    a.href = url;
    a.download = `match-plan-${stamp}.json`;
    document.body.appendChild(a);
    a.click();
    a.remove();
    URL.revokeObjectURL(url);
  }, [state]);

  const importJSON = useCallback((file) => {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => {
        try {
          const parsed = JSON.parse(reader.result);
          setState({ ...buildDefaultState(), ...parsed });
          resolve();
        } catch (e) {
          reject(e);
        }
      };
      reader.onerror = reject;
      reader.readAsText(file);
    });
  }, []);

  const resetAll = useCallback(() => {
    setState(buildDefaultState());
  }, []);

  const loadSample = useCallback(() => {
    setState(buildSampleState());
  }, []);

  // Reset just the gameplan-side state (keep teams, players, formation, labels)
  const resetGameplan = useCallback(() => {
    update((prev) => ({
      ...prev,
      gamePlan: {},
      teamFocus: { ballPlus: ["", ""], ballMinus: ["", ""] },
      playerNotes: {},
    }));
  }, [update]);

  const api = useMemo(() => ({
    state,
    setMatch,
    addPlayer, updatePlayer, removePlayer,
    togglePosition, setFormation, setPositionLabel,
    setTeamFocus, setPlayerNote,
    assignPlayer, clearAssignments,
    setActiveTab,
    exportJSON, importJSON,
    resetAll, loadSample, resetGameplan,
  }), [state, setMatch, addPlayer, updatePlayer, removePlayer, togglePosition, setFormation, setPositionLabel, setTeamFocus, setPlayerNote, assignPlayer, clearAssignments, setActiveTab, exportJSON, importJSON, resetAll, loadSample, resetGameplan]);
  return React.createElement(StoreContext.Provider, { value: api }, children);
}

function useStore() {
  const ctx = useContext(StoreContext);
  if (!ctx) throw new Error("useStore must be used within StoreProvider");
  return ctx;
}

// Derived helpers
function getAssignment(gp, p, h, pos) {
  return gp?.[p]?.[h]?.[pos] ?? null;
}

// Fair-playtime target per non-GK player:
//   (total playtime across all positions - one full-match goalkeeper) / players
function computeFairMinutes(state) {
  const { match, formation, players } = state;
  if (!players.length) return 0;
  const totalMatchMinutes = match.periods * match.periodMinutes;
  const totalPlayerTime = formation.length * totalMatchMinutes;
  const gkTime = totalMatchMinutes; // 1 GK plays the whole match
  return Math.round((totalPlayerTime - gkTime) / players.length);
}

function computePlayerStats(state) {
  const { match, players, formation, gamePlan } = state;
  const halfMinutes = match.periodMinutes / 2;
  const stats = {};
  for (const pl of players) {
    stats[pl.id] = { halves: [], totalMinutes: 0, positions: new Set() };
  }
  for (let p = 0; p < match.periods; p++) {
    for (let h = 0; h < 2; h++) {
      for (const pos of formation) {
        const pid = getAssignment(gamePlan, p, h, pos);
        if (pid && stats[pid]) {
          stats[pid].halves.push({ p, h, pos });
          stats[pid].totalMinutes += halfMinutes;
          stats[pid].positions.add(pos);
        }
      }
    }
  }
  return stats;
}

function computeSubInstructions(state) {
  const { match, formation, gamePlan, players } = state;
  const nameOf = (id) => players.find((p) => p.id === id)?.name || "—";
  const out = [];
  // index from 0 across all halves; compare half N to half N-1
  const totalHalves = match.periods * 2;
  for (let idx = 1; idx < totalHalves; idx++) {
    const p = Math.floor(idx / 2);
    const h = idx % 2;
    const prevP = Math.floor((idx - 1) / 2);
    const prevH = (idx - 1) % 2;
    const prevCell = gamePlan?.[prevP]?.[prevH] || {};
    const currCell = gamePlan?.[p]?.[h] || {};

    // Build playerId -> position maps for prev and curr
    const prevByPlayer = {};
    const currByPlayer = {};
    for (const pos of formation) {
      if (prevCell[pos]) prevByPlayer[prevCell[pos]] = pos;
      if (currCell[pos]) currByPlayer[currCell[pos]] = pos;
    }

    const events = [];
    // Outs: in prev but not in curr
    for (const pid of Object.keys(prevByPlayer)) {
      if (!(pid in currByPlayer)) {
        events.push({ type: "out", playerId: pid, name: nameOf(pid), fromPos: prevByPlayer[pid] });
      }
    }
    // Ins: in curr but not in prev
    for (const pid of Object.keys(currByPlayer)) {
      if (!(pid in prevByPlayer)) {
        events.push({ type: "in", playerId: pid, name: nameOf(pid), toPos: currByPlayer[pid] });
      }
    }
    // Switches: in both but different position
    for (const pid of Object.keys(currByPlayer)) {
      if (pid in prevByPlayer && prevByPlayer[pid] !== currByPlayer[pid]) {
        events.push({
          type: "switch", playerId: pid, name: nameOf(pid),
          fromPos: prevByPlayer[pid], toPos: currByPlayer[pid],
        });
      }
    }
    out.push({ periodIdx: p, halfIdx: h, events });
  }
  return out;
}

// Export to window
Object.assign(window, {
  StoreProvider, useStore,
  DEFAULT_POSITION_LABELS, POSITION_COORDS,
  computePlayerStats, computeSubInstructions, getAssignment, computeFairMinutes,
  uid,
});
