"use client";

import { createContext, ReactNode, useCallback, useContext, useEffect, useMemo, useState } from "react";
import { apiGet, getToken } from "@/lib/api";
import {
  getActiveBranchId,
  isSessionReady,
  SESSION_CHANGED_EVENT,
} from "@/lib/session-context";

export type ModuleCatalogItem = {
  key: string;
  label: string;
  enabled: boolean;
  platform_enabled: boolean;
  licensed: boolean;
};

type CachedCatalog = {
  branchId: number | null;
  savedAt: number;
  modules: ModuleCatalogItem[];
};

type ModulesContextValue = {
  modules: ModuleCatalogItem[];
  enabledKeys: string[] | null;
  refreshModules: (force?: boolean) => Promise<void>;
};

const CACHE_PREFIX = "admin_module_catalog:v2:";
const FRESH_MS = 60_000;
const MAX_AGE_MS = 5 * 60_000;

const ModulesContext = createContext<ModulesContextValue | null>(null);

function cacheStorageKey(branchId: number | null) {
  return `${CACHE_PREFIX}${branchId ?? "org"}`;
}

function readCatalogCache(branchId: number | null): CachedCatalog | null {
  if (typeof window === "undefined") return null;
  const raw = localStorage.getItem(cacheStorageKey(branchId));
  if (!raw) return null;
  try {
    const parsed = JSON.parse(raw) as CachedCatalog;
    if (!Array.isArray(parsed.modules) || typeof parsed.savedAt !== "number") return null;
    if (Date.now() - parsed.savedAt > MAX_AGE_MS) return null;
    return parsed;
  } catch {
    return null;
  }
}

function writeCatalogCache(branchId: number | null, modules: ModuleCatalogItem[]) {
  if (typeof window === "undefined") return;
  const payload: CachedCatalog = { branchId, savedAt: Date.now(), modules };
  localStorage.setItem(cacheStorageKey(branchId), JSON.stringify(payload));
}

function clearCatalogCache() {
  if (typeof window === "undefined") return;
  const keys: string[] = [];
  for (let i = 0; i < localStorage.length; i++) {
    const key = localStorage.key(i);
    if (key?.startsWith(CACHE_PREFIX)) keys.push(key);
  }
  keys.forEach((key) => localStorage.removeItem(key));
}

export function ModulesProvider({ children }: { children: ReactNode }) {
  const [modules, setModules] = useState<ModuleCatalogItem[]>([]);
  const [loaded, setLoaded] = useState(false);

  const refreshModules = useCallback(async (force = false) => {
    if (!getToken()) {
      clearCatalogCache();
      setModules([]);
      setLoaded(false);
      return;
    }
    if (!isSessionReady()) {
      return;
    }

    const branchId = getActiveBranchId();
    const cached = readCatalogCache(branchId);
    if (cached && !force) {
      setModules(cached.modules);
      setLoaded(true);
      if (Date.now() - cached.savedAt < FRESH_MS) return;
    }

    try {
      const rows = await apiGet<ModuleCatalogItem[]>("/module-catalog");
      setModules(rows);
      writeCatalogCache(branchId, rows);
    } catch {
      if (cached) {
        setModules(cached.modules);
      } else {
        setModules([]);
      }
    } finally {
      setLoaded(true);
    }
  }, []);

  useEffect(() => {
    void refreshModules();
    const onSession = () => {
      void refreshModules(true);
    };
    window.addEventListener(SESSION_CHANGED_EVENT, onSession);
    return () => window.removeEventListener(SESSION_CHANGED_EVENT, onSession);
  }, [refreshModules]);

  const enabledKeys = useMemo(
    () => (loaded ? modules.filter((row) => row.enabled).map((row) => row.key) : null),
    [loaded, modules],
  );

  const value = useMemo(
    () => ({ modules, enabledKeys, refreshModules }),
    [enabledKeys, modules, refreshModules],
  );

  return <ModulesContext.Provider value={value}>{children}</ModulesContext.Provider>;
}

export function useModules(): ModulesContextValue {
  return (
    useContext(ModulesContext) ?? {
      modules: [],
      enabledKeys: null,
      refreshModules: async () => {},
    }
  );
}
