// ============================================================
// BusManager — Store (Context + actions + persistence via API)
// ============================================================
const AppCtx = React.createContext(null);

const STORAGE_KEY = "busmanager_data_v2";
const STORAGE_USER = "busmanager_user_v2";
const DATA_KEYS = ["BUSES","DRIVERS","CUSTOMERS","CASH_CATS","RENTALS","CASH_TX","USERS","AUDIT","SETTINGS"];

const SNAPSHOTS = {};
DATA_KEYS.forEach(k => {
  SNAPSHOTS[k] = JSON.parse(JSON.stringify(window[k]));
});

function nextId(arr) { return arr.length ? Math.max(...arr.map(x => x.id || 0)) + 1 : 1; }

function pad(n, w) { return String(n).padStart(w, "0"); }
function todayISO() { return new Date().toISOString().slice(0,10); }

function buildKode(start, existing) {
  const dt = new Date(start);
  const yyyymm = `${pad(dt.getFullYear()%100,2)}${pad(dt.getMonth()+1,2)}`;
  const prefix = `SW-${yyyymm}`;
  const n = existing.filter(r => r.kode?.startsWith(prefix)).length + 1;
  return `${prefix}-${pad(n,3)}`;
}

// ---- API helpers ----
async function apiLoad() {
  try {
    const res = await fetch("/api/data");
    if (!res.ok) throw new Error("API error");
    return await res.json();
  } catch {
    return null;
  }
}

function apiSave() {
  const data = {};
  DATA_KEYS.forEach(k => { data[k] = window[k]; });
  fetch("/api/data", {
    method: "PUT",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(data),
  }).catch(() => {
    // fallback: save to localStorage if API fails
    try { localStorage.setItem(STORAGE_KEY, JSON.stringify(data)); } catch {}
  });
}

function AppProvider({ children }) {
  const [user, setUserState] = useState(null);
  const [version, setVersion] = useState(0);
  const [loading, setLoading] = useState(true);
  const loaded = useRef(false);

  // ---- LOAD on mount: try API first, then localStorage fallback ----
  useEffect(() => {
    (async () => {
      try {
        const apiData = await apiLoad();
        if (apiData && Object.keys(apiData).length > 0) {
          DATA_KEYS.forEach(k => {
            if (apiData[k] !== undefined) window[k] = apiData[k];
          });
        } else {
          // fallback to localStorage
          const saved = localStorage.getItem(STORAGE_KEY);
          if (saved) {
            const data = JSON.parse(saved);
            DATA_KEYS.forEach(k => {
              if (data[k] !== undefined) window[k] = data[k];
            });
            // push localStorage data to API so it's persisted server-side
            apiSave();
          }
        }
        const savedUser = localStorage.getItem(STORAGE_USER);
        if (savedUser) setUserState(JSON.parse(savedUser));
      } catch (e) {
        console.warn("[Store] Load failed", e);
      }
      loaded.current = true;
      setLoading(false);
      setVersion(v => v + 1);
    })();
  }, []);

  // ---- Persistence ----
  const persist = useCallback(() => {
    if (!loaded.current) return;
    apiSave();
  }, []);

  const setUser = useCallback((u) => {
    setUserState(u);
    if (u) localStorage.setItem(STORAGE_USER, JSON.stringify(u));
    else localStorage.removeItem(STORAGE_USER);
  }, []);

  // ---- bump: persist + re-render + optional audit ----
  const bump = useCallback((auditEntry) => {
    if (auditEntry) {
      const id = nextId(window.AUDIT);
      window.AUDIT = [
        { id, ts: new Date().toISOString(), user: user?.nama || "—", ...auditEntry },
        ...window.AUDIT,
      ].slice(0, 200);
    }
    persist();
    setVersion(v => v + 1);
  }, [user, persist]);

  // ---- ACTIONS ----
  const actions = useMemo(() => ({

    // ---- BUS ----
    saveBus: (bus) => {
      if (bus.id) {
        window.BUSES = window.BUSES.map(b => b.id === bus.id ? { ...b, ...bus } : b);
        bump({ action: "Update", model: "Bus", target: bus.kode, desc: "Update data unit" });
      } else {
        const id = nextId(window.BUSES);
        window.BUSES = [...window.BUSES, { ...bus, id }];
        bump({ action: "Create", model: "Bus", target: bus.kode, desc: "Unit baru" });
      }
    },
    deleteBus: (id) => {
      const b = window.BUSES.find(x => x.id === id);
      const inUse = window.RENTALS.some(r => r.busId === id && r.status !== "batal" && r.status !== "selesai");
      if (inUse) throw new Error(`Tidak bisa hapus — ${b?.kode} masih punya sewa aktif.`);
      window.BUSES = window.BUSES.filter(x => x.id !== id);
      bump({ action: "Delete", model: "Bus", target: b?.kode || `#${id}` });
    },

    // ---- DRIVER ----
    saveDriver: (d) => {
      if (d.id) {
        window.DRIVERS = window.DRIVERS.map(x => x.id === d.id ? { ...x, ...d } : x);
        bump({ action: "Update", model: "Sopir", target: d.nama });
      } else {
        const id = nextId(window.DRIVERS);
        window.DRIVERS = [...window.DRIVERS, { ...d, id }];
        bump({ action: "Create", model: "Sopir", target: d.nama, desc: "Sopir baru" });
      }
    },
    deleteDriver: (id) => {
      const d = window.DRIVERS.find(x => x.id === id);
      window.DRIVERS = window.DRIVERS.filter(x => x.id !== id);
      bump({ action: "Delete", model: "Sopir", target: d?.nama });
    },

    // ---- CUSTOMER ----
    saveCustomer: (c) => {
      if (c.id) {
        window.CUSTOMERS = window.CUSTOMERS.map(x => x.id === c.id ? { ...x, ...c } : x);
        bump({ action: "Update", model: "Penyewa", target: c.nama });
        return window.CUSTOMERS.find(x => x.id === c.id);
      } else {
        const id = nextId(window.CUSTOMERS);
        const newC = { ...c, id };
        window.CUSTOMERS = [...window.CUSTOMERS, newC];
        bump({ action: "Create", model: "Penyewa", target: c.nama, desc: "Penyewa baru" });
        return newC;
      }
    },
    deleteCustomer: (id) => {
      const c = window.CUSTOMERS.find(x => x.id === id);
      const inUse = window.RENTALS.some(r => r.customerId === id);
      if (inUse) throw new Error(`Penyewa "${c?.nama}" punya riwayat sewa — tidak bisa dihapus.`);
      window.CUSTOMERS = window.CUSTOMERS.filter(x => x.id !== id);
      bump({ action: "Delete", model: "Penyewa", target: c?.nama });
    },

    // ---- CATEGORY ----
    saveCat: (c) => {
      if (c.id) {
        window.CASH_CATS = window.CASH_CATS.map(x => x.id === c.id ? { ...x, ...c } : x);
        bump({ action: "Update", model: "Kategori", target: c.nama });
      } else {
        const id = nextId(window.CASH_CATS);
        window.CASH_CATS = [...window.CASH_CATS, { ...c, id, seeded: false }];
        bump({ action: "Create", model: "Kategori", target: c.nama });
      }
    },
    deleteCat: (id) => {
      const c = window.CASH_CATS.find(x => x.id === id);
      if (c?.seeded) throw new Error("Kategori bawaan sistem tidak dapat dihapus.");
      const inUse = window.CASH_TX.some(t => t.catId === id);
      if (inUse) throw new Error(`Kategori "${c?.nama}" sudah dipakai di transaksi kas.`);
      window.CASH_CATS = window.CASH_CATS.filter(x => x.id !== id);
      bump({ action: "Delete", model: "Kategori", target: c?.nama });
    },

    // ---- RENTAL (with auto-kas) ----
    saveRental: (rental) => {
      const isNew = !rental.id;
      let saved;
      if (isNew) {
        const id = nextId(window.RENTALS);
        const kode = buildKode(rental.start, window.RENTALS);
        saved = { ...rental, id, kode };
        window.RENTALS = [...window.RENTALS, saved];
        bump({ action: "Create", model: "Sewa", target: kode, desc: `Penyewa: ${window.CUSTOMERS.find(c => c.id === rental.customerId)?.nama || "—"}` });
      } else {
        const prev = window.RENTALS.find(r => r.id === rental.id);
        saved = { ...prev, ...rental };
        window.RENTALS = window.RENTALS.map(r => r.id === rental.id ? saved : r);
        if (prev.status !== saved.status) {
          bump({ action: "Update", model: "Sewa", target: saved.kode, desc: `Status: ${window.STATUS_LABEL[prev.status]} → ${window.STATUS_LABEL[saved.status]}` });
        } else {
          bump({ action: "Update", model: "Sewa", target: saved.kode });
        }
      }

      // Auto cash generation
      const dpCatId = window.CASH_CATS.find(c => c.nama === "Pendapatan Sewa")?.id || 1;
      const existingAuto = window.CASH_TX.filter(t => t.rentalId === saved.id && t.isAuto);
      const sumExisting = existingAuto.reduce((s,t) => s + t.jumlah, 0);

      let target = 0;
      if (saved.status === "dp") target = saved.dp || 0;
      else if (saved.status === "lunas" || saved.status === "selesai") target = saved.harga || 0;

      const delta = target - sumExisting;
      const cust = window.CUSTOMERS.find(c => c.id === saved.customerId);
      if (delta > 0) {
        const id = nextId(window.CASH_TX);
        const desc = saved.status === "lunas" || saved.status === "selesai"
          ? `Pelunasan ${saved.kode} (${cust?.nama || "—"})`
          : `DP sewa ${saved.kode} (${cust?.nama || "—"})`;
        window.CASH_TX = [...window.CASH_TX, {
          id,
          tanggal: todayISO(),
          catId: dpCatId,
          tipe: "masuk",
          deskripsi: desc,
          jumlah: delta,
          isAuto: true,
          rentalId: saved.id,
        }];
      }

      persist();
      setVersion(v => v + 1);
      return saved;
    },

    cancelRental: (id) => {
      const r = window.RENTALS.find(x => x.id === id);
      if (!r) return;
      window.RENTALS = window.RENTALS.map(x => x.id === id ? { ...x, status: "batal" } : x);
      bump({ action: "Cancel", model: "Sewa", target: r.kode, desc: `Status: ${window.STATUS_LABEL[r.status]} → Batal` });
    },

    deleteRental: (id) => {
      const r = window.RENTALS.find(x => x.id === id);
      window.RENTALS = window.RENTALS.filter(x => x.id !== id);
      window.CASH_TX = window.CASH_TX.filter(t => !(t.rentalId === id && t.isAuto));
      bump({ action: "Delete", model: "Sewa", target: r?.kode, desc: "Hapus sewa & entry kas auto" });
    },

    // ---- CASH ----
    saveCashTx: (t) => {
      if (t.id) {
        const prev = window.CASH_TX.find(x => x.id === t.id);
        if (prev?.isAuto) throw new Error("Transaksi auto tidak bisa di-edit langsung — edit lewat modul Sewa.");
        window.CASH_TX = window.CASH_TX.map(x => x.id === t.id ? { ...x, ...t } : x);
        bump({ action: "Update", model: "Kas", target: t.deskripsi });
      } else {
        const id = nextId(window.CASH_TX);
        window.CASH_TX = [...window.CASH_TX, { ...t, id, isAuto: false }];
        bump({ action: "Create", model: t.tipe === "masuk" ? "Kas Masuk" : "Kas Keluar", target: t.deskripsi, desc: window.RP(t.jumlah) });
      }
    },
    deleteCashTx: (id) => {
      const t = window.CASH_TX.find(x => x.id === id);
      if (t?.isAuto) throw new Error("Transaksi auto tidak bisa dihapus langsung.");
      window.CASH_TX = window.CASH_TX.filter(x => x.id !== id);
      bump({ action: "Delete", model: "Kas", target: t?.deskripsi });
    },

    // ---- USER ----
    saveUser: (u) => {
      if (u.id) {
        window.USERS = window.USERS.map(x => x.id === u.id ? { ...x, ...u } : x);
        bump({ action: "Update", model: "User", target: u.nama });
      } else {
        const id = nextId(window.USERS);
        const inisial = u.nama.split(" ").slice(0,2).map(s => s[0]).join("").toUpperCase();
        window.USERS = [...window.USERS, { ...u, id, inisial, aktif: true }];
        bump({ action: "Create", model: "User", target: u.nama, desc: `Role: ${u.role}` });
      }
    },
    deleteUser: (id) => {
      const u = window.USERS.find(x => x.id === id);
      if (u?.role === "Admin" && window.USERS.filter(x => x.role === "Admin").length <= 1)
        throw new Error("Tidak bisa hapus admin terakhir.");
      window.USERS = window.USERS.filter(x => x.id !== id);
      bump({ action: "Delete", model: "User", target: u?.nama });
    },

    // ---- SETTINGS ----
    saveSettings: (s) => {
      window.SETTINGS = { ...window.SETTINGS, ...s };
      bump({ action: "Update", model: "Settings", target: "Profil Perusahaan" });
    },

    // ---- DATA MANAGEMENT ----
    resetAllData: () => {
      DATA_KEYS.forEach(k => {
        window[k] = JSON.parse(JSON.stringify(SNAPSHOTS[k]));
      });
      // Reset both API and localStorage
      fetch("/api/reset", { method: "POST" }).catch(() => {});
      localStorage.removeItem(STORAGE_KEY);
      bump({ action: "Reset", model: "System", target: "Semua data", desc: "Reset ke data demo awal" });
    },

    backup: () => {
      const data = {};
      DATA_KEYS.forEach(k => { data[k] = window[k]; });
      data.timestamp = new Date().toISOString();
      const blob = new Blob([JSON.stringify(data, null, 2)], { type: "application/json" });
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = `busmanager-backup-${todayISO()}.json`;
      a.click();
      URL.revokeObjectURL(url);
      bump({ action: "Backup", model: "System", target: "Database", desc: "Backup manual" });
    },
  }), [bump, persist]);

  if (loading) {
    return React.createElement("div", {
      style: {
        display: "flex", alignItems: "center", justifyContent: "center",
        height: "100vh", fontFamily: "Plus Jakarta Sans, sans-serif",
        color: "#6a7388", fontSize: 14, gap: 10,
      }
    },
      React.createElement("div", {
        style: {
          width: 20, height: 20, border: "3px solid #e6e9ef",
          borderTopColor: "#1b4a8f", borderRadius: "50%",
          animation: "spin 0.6s linear infinite",
        }
      }),
      "Memuat data..."
    );
  }

  return (
    <AppCtx.Provider value={{ user, setUser, version, actions }}>
      {children}
    </AppCtx.Provider>
  );
}

function useApp() {
  const ctx = useContext(AppCtx);
  if (!ctx) throw new Error("useApp must be used inside AppProvider");
  return ctx;
}

window.AppProvider = AppProvider;
window.useApp = useApp;
