import { createContext, useContext, useState, useMemo, useRef } from "react";
import JSZip from "jszip";
import { INITIAL_DATA } from "../constants/index.js";
import { migrateData } from "../utils/storage.js";
import { useTheme } from "../hooks/useTheme.js";

const AppContext = createContext(null);

// ── API helpers ───────────────────────────────────────────────────────────────
const getToken  = () => localStorage.getItem("vf_token");
const authHdrs  = () => ({ "Content-Type": "application/json", Authorization: `Bearer ${getToken()}` });

async function apiFetch(path, options = {}) {
  const res = await fetch(`/api${path}`, { ...options, headers: { ...authHdrs(), ...(options.headers || {}) } });
  if (!res.ok) throw new Error(`API ${path} → ${res.status}`);
  return res.json();
}

// ── Provider ──────────────────────────────────────────────────────────────────
export function AppProvider({ children }) {
  // ── Auth ──────────────────────────────────────────────────────
  const [loggedIn,     setLoggedIn]     = useState(false);
  const [currentUser,  setCurrentUser]  = useState(null);
  const [loading,      setLoading]      = useState(false);
  const [avatar, setAvatarRaw] = useState(null);

  const setAvatar = async (base64) => {
    setAvatarRaw(base64);
    try {
      await apiFetch("/auth/me/avatar", { method: "PATCH", body: JSON.stringify({ avatar: base64 ?? null }) });
    } catch (err) {
      console.error("Avatar opslaan mislukt:", err);
    }
  };

  // ── UI ────────────────────────────────────────────────────────
  const [darkMode,  setDarkMode]  = useState(true);
  const [locked,    setLocked]    = useState(false);
  const [tab,       setTab]       = useState(0);
  const [menuOpen,  setMenuOpen]  = useState(false);
  const [showUsers, setShowUsers] = useState(false);

  // ── Financiële data ───────────────────────────────────────────
  const [data,                 setDataRaw]                = useState(INITIAL_DATA);
  const [evRows,               setEvRowsRaw]               = useState([]);
  const [evVoortgangHistory,   setEvVoortgangHistoryRaw]   = useState([]);
  const saveTimer = useRef(null);

  const saveToApi = (newData, newEvRows, newEvVH) => {
    if (saveTimer.current) clearTimeout(saveTimer.current);
    saveTimer.current = setTimeout(async () => {
      try {
        await apiFetch("/data", {
          method: "PUT",
          body: JSON.stringify({ ...newData, evVoortgang: newEvRows, evVoortgangHistory: newEvVH }),
        });
      } catch (err) {
        console.error("Opslaan mislukt:", err);
      }
    }, 800);
  };

  const setData = (next) => {
    const d = typeof next === "function" ? next(data) : next;
    setDataRaw(d);
    saveToApi(d, evRows, evVoortgangHistory);
  };

  const setEvRows = (rows) => {
    const r = typeof rows === "function" ? rows(evRows) : rows;
    setEvRowsRaw(r);
    saveToApi(data, r, evVoortgangHistory);
  };

  const setEvVoortgangHistory = (history) => {
    const h = typeof history === "function" ? history(evVoortgangHistory) : history;
    setEvVoortgangHistoryRaw(h);
    saveToApi(data, evRows, h);
  };

  // ── Gebruikers ────────────────────────────────────────────────
  const [users, setUsersRaw] = useState(() => {
    try { return JSON.parse(localStorage.getItem("wbjw_users")) || []; } catch { return []; }
  });
  const setUsers = (u) => { localStorage.setItem("wbjw_users", JSON.stringify(u)); setUsersRaw(u); };

  // ── Thema ─────────────────────────────────────────────────────
  const T = useTheme(darkMode);

  // ── Afgeleide waarden ─────────────────────────────────────────
  const ev            = data.eigenVermogen;
  const schuld        = data.schuld;
  const cats          = ev?.categories       || [];
  const schuldBlokken = schuld?.blokken      || [];
  const schuldHistory = schuld?.schuldHistory || [];

  const totEV = useMemo(
    () => cats.reduce((a, c) => a + c.items.reduce((b, i) => b + (i.waarde || 0), 0), 0),
    [cats]
  );
  const totSchuld = useMemo(
    () => schuldBlokken.reduce((a, b) => a + b.items.reduce((c, i) => c + (i.waarde || 0), 0), 0),
    [schuldBlokken]
  );
  const catTotals = useMemo(
    () => cats.map((c) => ({ ...c, tot: c.items.reduce((a, i) => a + (i.waarde || 0), 0) })),
    [cats]
  );

  // ── Auth handlers ─────────────────────────────────────────────
  const login = async (user) => {
    setCurrentUser(user);
    setLoggedIn(true);
    setAvatarRaw(user.avatar ?? null);
    setLoading(true);
    try {
      const apiData = await apiFetch("/data");
      const migrated = migrateData({
        eigenVermogen: apiData.eigenVermogen,
        schuld:        apiData.schuld,
      });
      setDataRaw(migrated);
      setEvRowsRaw(apiData.evVoortgang || []);
      setEvVoortgangHistoryRaw(apiData.evVoortgangHistory || []);
    } catch (err) {
      console.error("Data laden mislukt:", err);
    } finally {
      setLoading(false);
    }
  };

  const updateProfile = async (naam, email) => {
    const res = await apiFetch("/auth/me", { method: "PATCH", body: JSON.stringify({ naam, email }) });
    localStorage.setItem("vf_token", res.token);
    setCurrentUser(res.user);
  };

  const changePassword = async (huidig, nieuw) => {
    await apiFetch("/auth/me/password", { method: "POST", body: JSON.stringify({ huidig, nieuw }) });
  };

  const logout = () => {
    setCurrentUser(null);
    setAvatarRaw(null);
    setLoggedIn(false);
    setDataRaw(INITIAL_DATA);
    setEvRowsRaw([]);
    setEvVoortgangHistoryRaw([]);
    localStorage.removeItem("vf_token");
    if (saveTimer.current) clearTimeout(saveTimer.current);
  };

  // ── Backup / restore ──────────────────────────────────────────
  const doBackup = async () => {
    const zip   = new JSZip();
    const datum = new Date().toISOString().slice(0, 10);
    zip.file("data.json", JSON.stringify({ ...data, evVoortgang: evRows, evVoortgangHistory }, null, 2));
    zip.file("meta.json", JSON.stringify({ versie: 1, datum, app: "vibefinance", gebruiker: currentUser?.email }, null, 2));
    const blob = await zip.generateAsync({ type: "blob", compression: "DEFLATE" });
    const url  = URL.createObjectURL(blob);
    const a    = document.createElement("a");
    a.href     = url;
    a.download = `vibefinance_backup_${datum}.zip`;
    a.click();
    URL.revokeObjectURL(url);
  };

  const doRestore = () => {
    const input  = document.createElement("input");
    input.type   = "file";
    input.accept = ".zip";
    input.onchange = async (e) => {
      const file = e.target.files[0];
      if (!file) return;
      try {
        const zip   = await JSZip.loadAsync(file);
        const entry = zip.file("data.json");
        if (!entry) throw new Error("Geen data.json gevonden in backup.");
        const parsed    = JSON.parse(await entry.async("string"));
        const migrated  = migrateData({ eigenVermogen: parsed.eigenVermogen, schuld: parsed.schuld });
        const newEvRows = parsed.evVoortgang || [];
        const newEvVH   = parsed.evVoortgangHistory || [];
        setDataRaw(migrated);
        setEvRowsRaw(newEvRows);
        setEvVoortgangHistoryRaw(newEvVH);
        await apiFetch("/data", {
          method: "PUT",
          body: JSON.stringify({ ...migrated, evVoortgang: newEvRows, evVoortgangHistory: newEvVH }),
        });
      } catch (err) { alert("Ongeldig of beschadigd backup-bestand: " + err.message); }
    };
    input.click();
  };

  return (
    <AppContext.Provider value={{
      loggedIn, currentUser, login, logout, loading, updateProfile, changePassword,
      avatar, setAvatar,
      darkMode, setDarkMode,
      locked, setLocked,
      tab, setTab,
      menuOpen, setMenuOpen,
      showUsers, setShowUsers,
      T,
      data, setData,
      ev, schuld, cats, schuldBlokken, schuldHistory,
      totEV, totSchuld, catTotals,
      evRows, setEvRows,
      evVoortgangHistory, setEvVoortgangHistory,
      users, setUsers,
      doBackup, doRestore,
    }}>
      {children}
    </AppContext.Provider>
  );
}

export const useApp = () => {
  const ctx = useContext(AppContext);
  if (!ctx) throw new Error("useApp must be used inside <AppProvider>");
  return ctx;
};
