// Data store — fetches employer/employees/runs/whk from the backend (Supabase-backed).
// Exposes the same window.LS_* globals the rest of the app already uses.
// Keeps a hardcoded FALLBACK so the UI still renders if the DB isn't reachable.

const fmt = {
  euro(n, { sign = false, always = false } = {}) {
    if (n === null || n === undefined || isNaN(n)) return "—";
    const abs = Math.abs(n);
    const s = abs.toLocaleString("nl-NL", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
    const pre = n < 0 ? "−" : (sign || always ? "+" : "");
    return `€\u00a0${pre === "−" ? "−" : (always ? pre : "")}${s}`.replace("−", "−");
  },
  eurSigned(n) {
    if (n === null || n === undefined) return "—";
    const abs = Math.abs(Number(n));
    const s = abs.toLocaleString("nl-NL", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
    return Number(n) < 0 ? `−€\u00a0${s}` : `€\u00a0${s}`;
  },
  eurPlain(n) {
    const s = Math.abs(Number(n)).toLocaleString("nl-NL", { minimumFractionDigits: 0, maximumFractionDigits: 0 });
    return `€\u00a0${s}`;
  },
  pct(n, d = 3) { return `${Number(n).toLocaleString("nl-NL", { minimumFractionDigits: d, maximumFractionDigits: d })}%`; },
  bsn() { return "●●●●●●●●●"; },
  iban(i) { return i; },
  date(d) {
    if (!d) return "—";
    const m = ["jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec"];
    const dt = new Date(d);
    if (isNaN(dt.getTime())) return String(d);
    return `${dt.getDate()} ${m[dt.getMonth()]} ${dt.getFullYear()}`;
  },
  monthNL(mi) {
    return ["januari","februari","maart","april","mei","juni","juli","augustus","september","oktober","november","december"][mi - 1];
  },
};

// Client-side approximation used only for UI estimates when we don't have a
// server-computed payslip yet (dashboard preview, employee-detail estimate).
// Authoritative numbers always come from /api/runs on the server.
function computePayslip(emp) {
  const bruto = Number(emp.base_salary);
  const loonheffing = -Math.round(bruto * (emp.bt_pct >= 49 ? 0.2567 : 0.1893) * 100) / 100;
  const zvw_pct = 5.32;
  const zvw = -Math.round(bruto * (zvw_pct / 100) * 100) / 100;
  const net = Math.round((bruto + loonheffing + zvw) * 100) / 100;
  return { bruto, loonheffing, zvw, zvw_pct, net, arbeidskorting: 411 * (emp.parttime / 100) * 12 };
}

// ——— Fallback demo data (used if API unreachable) ———
const FALLBACK_EMPLOYER = {
  id: "ehold", legal_name: "Ehold B.V.", kvk: "84217390",
  address: "Herenweg 14", postcode: "3703 AS", city: "Zeist",
  email: "hr@ehold.nl", admin_email: "administratie@ehold.nl",
  loonadministratie_nr: "26130", loonheffingen_nr: "811518772L02",
  iban: "NL88 RABO 0300 8814 22", cao: "Geen (eigen arbeidsvoorwaarden)",
  subdomain: "ehold.loonstrook.nl",
};

const FALLBACK_EMPLOYEES = [
  { id: "e1", number: "00001", first_name: "AC", last_name: "Sjamaar-Huber", email: "ac@ehold.nl", bsn: "123456789", dob: "1969-02-24", address: "Daniel Marotplein 3", postcode: "3703 DC", city: "Zeist", iban: "NL40 RABO 0360 2681 02", function: "Directeur", hired_at: "2026-01-01", terminated_at: null, base_salary: 4833.34, parttime: 100, hours: 174.00, lh_table: "Witte tabel", heffingskorting: true, bt_pct: 50.470, jaarloon_bt: 56000, avatar_color: "oklch(75% 0.07 30)", status: "actief" },
];

const FALLBACK_RUNS = [
  { id: "r2026-03", year: 2026, period: 3, label: "maart 2026", status: "archived", confirmed_at: "2026-03-25", employees_count: 6, rules_version: "v2026.1" },
];

// ——— API helper ———
async function getJSON(url) {
  const r = await fetch(url);
  if (!r.ok) throw new Error(`GET ${url} → ${r.status}`);
  return r.json();
}

function normalizeRun(r) {
  // Map DB snake_case + numeric strings to what the UI expects.
  return {
    id: r.id, year: Number(r.year), period: Number(r.period),
    label: r.label || `${fmt.monthNL(Number(r.period))} ${r.year}`,
    status: r.status,
    confirmed_at: r.confirmed_at,
    employees: Number(r.employees_count || 0),
    employees_count: Number(r.employees_count || 0),
    rules_version: r.rules_version,
    total_bruto: Number(r.total_bruto || 0),
    total_heffing: Number(r.total_heffing || 0),
    total_zvw: Number(r.total_zvw || 0),
    total_net: Number(r.total_net || 0),
  };
}

// ——— Store ———
const LS_store = {
  loaded: false,
  error: null,
  dbOk: true,
  async load() {
    try {
      const [employer, employees, runs, whk, health, me, notifications] = await Promise.all([
        getJSON("/api/employer").catch(() => null),
        getJSON("/api/employees").catch(() => []),
        getJSON("/api/runs").catch(() => []),
        getJSON("/api/whk").catch(() => null),
        getJSON("/api/health").catch(() => ({ db: false })),
        getJSON("/api/me/payslips").catch(() => null),
        getJSON("/api/notifications").catch(() => []),
      ]);
      const usingFallbackEmps = !(Array.isArray(employees) && employees.length);
      const usingFallbackRuns = !(Array.isArray(runs) && runs.length);
      const emps = usingFallbackEmps ? FALLBACK_EMPLOYEES : employees.map(e => ({
        ...e, base_salary: Number(e.base_salary), hours: Number(e.hours),
        bt_pct: Number(e.bt_pct), jaarloon_bt: Number(e.jaarloon_bt),
      }));
      const runList = usingFallbackRuns ? FALLBACK_RUNS.map(normalizeRun) : runs.map(normalizeRun);
      this.dbOk = !!(health && health.db);
      Object.assign(window, {
        LS_employer: employer || FALLBACK_EMPLOYER,
        LS_employees: emps,
        LS_runs: runList,
        LS_whk: whk || null,
        LS_health: health,
        LS_mePayslips: me,
        LS_notifications: Array.isArray(notifications) ? notifications : [],
      });
      this.loaded = true;
    } catch (e) {
      console.error("LS_store.load failed:", e);
      this.error = e.message;
      this.dbOk = false;
      Object.assign(window, {
        LS_employer: FALLBACK_EMPLOYER,
        LS_employees: FALLBACK_EMPLOYEES,
        LS_runs: FALLBACK_RUNS.map(normalizeRun),
        LS_whk: null, LS_health: { db: false },
        LS_mePayslips: null,
        LS_notifications: [],
      });
      this.loaded = true;
    }
  },
  async refreshEmployees() {
    const employees = await getJSON("/api/employees").catch(() => []);
    if (Array.isArray(employees) && employees.length) {
      window.LS_employees = employees.map(e => ({
        ...e, base_salary: Number(e.base_salary), hours: Number(e.hours),
        bt_pct: Number(e.bt_pct), jaarloon_bt: Number(e.jaarloon_bt),
      }));
    }
  },
  async refreshRuns() {
    const runs = await getJSON("/api/runs").catch(() => []);
    if (Array.isArray(runs) && runs.length) window.LS_runs = runs.map(normalizeRun);
  },
  async refreshWhk() {
    window.LS_whk = await getJSON("/api/whk").catch(() => null);
  },
  async refreshEmployer() {
    const e = await getJSON("/api/employer").catch(() => null);
    if (e) window.LS_employer = e;
  },
  async refreshNotifications() {
    const n = await getJSON("/api/notifications").catch(() => []);
    window.LS_notifications = Array.isArray(n) ? n : [];
  },
};

// Current period = next month after latest archived, else April 2026
function deriveCurrentPeriod() {
  const runs = window.LS_runs || [];
  const last = runs[0];
  let year = 2026, period = 4;
  if (last) {
    period = last.period + 1;
    year = last.year;
    if (period > 12) { period = 1; year++; }
  }
  return { year, period, label: `${fmt.monthNL(period)} ${year}` };
}

Object.assign(window, {
  LS_employer: FALLBACK_EMPLOYER,
  LS_employees: FALLBACK_EMPLOYEES,
  LS_runs: FALLBACK_RUNS.map(normalizeRun),
  LS_currentPeriod: { year: 2026, period: 4, label: "april 2026" },
  LS_fmt: fmt,
  LS_computePayslip: computePayslip,
  LS_store,
  LS_deriveCurrentPeriod: deriveCurrentPeriod,
  LS_notifications: [],
  LS_mePayslips: null,
});
