// Rôle : synchronise les toolboxes, données d'outils, liens de jeux et quota via IndexedDB.
import { useEffect, useState } from "react";
import {
  getAllModuleData as dbGetAllModuleData,
  getLinks as dbGetLinks,
  getSetting as dbGetSetting,
  getStorageEstimate,
  getToolboxes as dbGetToolboxes,
  removeModuleData as dbRemoveModuleData,
  removeModuleDataKeys as dbRemoveModuleDataKeys,
  setLinks as dbSetLinks,
  setModuleData as dbSetModuleData,
  setSetting as dbSetSetting,
  setToolboxes as dbSetToolboxes
} from "../../../utils/indexedDbStorage.js";
import {
  compactToolboxesForStorage,
  moduleStorageKey,
  normalizeToolbox,
  prepareModuleDataForStorage
} from "./toolboxStorage.js";

export function useIndexedToolboxes(onError) {
  const [ready, setReady] = useState(false);
  const [toolboxes, setToolboxesState] = useState([]);
  const [links, setLinksState] = useState({});
  const [moduleData, setModuleDataState] = useState({});
  const [toastPosition, setToastPositionState] = useState("right");
  const [storageUsage, setStorageUsage] = useState({ used: 0, limit: 0, ratio: 0 });

  async function refreshQuota() {
    try {
      const estimate = await getStorageEstimate();
      const used = estimate.usage || 0;
      const limit = estimate.quota || 0;
      setStorageUsage({ used, limit, ratio: limit ? Math.min(1, used / limit) : 0 });
    } catch {
      setStorageUsage({ used: 0, limit: 0, ratio: 0 });
    }
  }

  useEffect(() => {
    let cancelled = false;
    async function loadStore() {
      try {
        const [storedToolboxes, storedLinks, storedModules, storedToastPosition] = await Promise.all([
          dbGetToolboxes(),
          dbGetLinks(),
          dbGetAllModuleData(),
          dbGetSetting("toastPosition", "right")
        ]);
        if (cancelled) return;
        setToolboxesState((Array.isArray(storedToolboxes) ? storedToolboxes : []).map(normalizeToolbox).filter(Boolean));
        setLinksState(storedLinks && typeof storedLinks === "object" ? storedLinks : {});
        setModuleDataState(Object.fromEntries((storedModules || []).map((entry) => [entry.key, entry.data])));
        setToastPositionState(storedToastPosition === "left" ? "left" : "right");
        setReady(true);
        refreshQuota();
      } catch (error) {
        if (!cancelled) {
          setReady(true);
          onError(error.message || "Stockage IndexedDB indisponible.");
        }
      }
    }
    loadStore();
    return () => { cancelled = true; };
  }, []);

  function persistToolboxes(nextToolboxes) {
    const normalized = compactToolboxesForStorage(nextToolboxes).map(normalizeToolbox).filter(Boolean);
    setToolboxesState(normalized);
    dbSetToolboxes(compactToolboxesForStorage(normalized))
      .then(refreshQuota)
      .catch((error) => onError(error.message));
    return true;
  }

  function persistLinks(nextLinks) {
    setLinksState(nextLinks);
    dbSetLinks(nextLinks)
      .then(refreshQuota)
      .catch((error) => onError(error.message));
    return true;
  }

  function getModuleData(toolboxId, moduleId, fallback) {
    const value = moduleData[moduleStorageKey(toolboxId, moduleId)];
    return value == null ? fallback : value;
  }

  function updateModuleData(toolboxId, moduleId, value, moduleType = "") {
    const compact = prepareModuleDataForStorage(toolboxes, toolboxId, moduleId, value, moduleType);
    const key = moduleStorageKey(toolboxId, moduleId);
    setModuleDataState((state) => {
      const nextState = { ...state };
      if (compact == null) delete nextState[key];
      else nextState[key] = compact;
      return nextState;
    });
    const operation = compact == null ? dbRemoveModuleData(key) : dbSetModuleData(key, compact);
    operation.then(refreshQuota).catch((error) => onError(error.message));
    return true;
  }

  function removeModuleData(toolboxId, moduleId) {
    const key = moduleStorageKey(toolboxId, moduleId);
    setModuleDataState((state) => {
      const nextState = { ...state };
      delete nextState[key];
      return nextState;
    });
    dbRemoveModuleData(key).then(refreshQuota).catch((error) => onError(error.message));
  }

  function removeToolboxModuleData(toolbox) {
    const keys = (toolbox?.modules || []).map((module) => moduleStorageKey(toolbox.id, module.id));
    setModuleDataState((state) => {
      const nextState = { ...state };
      keys.forEach((key) => delete nextState[key]);
      return nextState;
    });
    dbRemoveModuleDataKeys(keys).then(refreshQuota).catch((error) => onError(error.message));
  }

  function setToastPosition(position) {
    const normalized = position === "left" ? "left" : "right";
    setToastPositionState(normalized);
    dbSetSetting("toastPosition", normalized)
      .then(refreshQuota)
      .catch((error) => onError(error.message));
  }

  return {
    ready,
    toolboxes,
    links,
    moduleData,
    toastPosition,
    storageUsage,
    setToolboxes: persistToolboxes,
    setLinks: persistLinks,
    getModuleData,
    updateModuleData,
    removeModuleData,
    removeToolboxModuleData,
    setToastPosition,
    refreshQuota
  };
}
