import { createContext, useContext, useCallback, type ReactNode } from "react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { moduleService } from "../services/moduleService";
import type {
  ModuleDto,
  EnableModuleRequest,
  SubscriptionDto,
} from "../types/module";

// ==================== TYPES ====================

export interface ModuleContextValue {
  /** Lista di tutti i moduli disponibili */
  modules: ModuleDto[];
  /** Lista dei moduli attualmente attivi */
  activeModules: ModuleDto[];
  /** Codici dei moduli attivi (per filtro veloce) */
  activeModuleCodes: string[];
  /** Stato di caricamento */
  isLoading: boolean;
  /** Errore di caricamento */
  error: Error | null;
  /** Verifica se un modulo è abilitato */
  isModuleEnabled: (code: string) => boolean;
  /** Ottiene un modulo per codice */
  getModule: (code: string) => ModuleDto | undefined;
  /** Attiva un modulo */
  enableModule: (
    code: string,
    request: EnableModuleRequest,
  ) => Promise<SubscriptionDto>;
  /** Disattiva un modulo */
  disableModule: (code: string) => Promise<void>;
  /** Ricarica i dati dei moduli */
  refreshModules: () => Promise<void>;
}

const ModuleContext = createContext<ModuleContextValue | null>(null);

// ==================== PROVIDER ====================

interface ModuleProviderProps {
  children: ReactNode;
}

export function ModuleProvider({ children }: ModuleProviderProps) {
  const queryClient = useQueryClient();

  // Query per tutti i moduli
  const {
    data: modules = [],
    isLoading: isLoadingModules,
    error: modulesError,
  } = useQuery({
    queryKey: ["modules"],
    queryFn: moduleService.getAll,
    staleTime: 5 * 60 * 1000, // 5 minuti
    refetchOnWindowFocus: false,
  });

  // Query per moduli attivi
  const {
    data: activeModules = [],
    isLoading: isLoadingActive,
    error: activeError,
  } = useQuery({
    queryKey: ["modules", "active"],
    queryFn: moduleService.getActive,
    staleTime: 5 * 60 * 1000,
    refetchOnWindowFocus: false,
  });

  // Calcola i codici dei moduli attivi
  const activeModuleCodes = activeModules.map((m) => m.code);

  // Verifica se un modulo è abilitato
  const isModuleEnabled = useCallback(
    (code: string): boolean => {
      return activeModuleCodes.includes(code);
    },
    [activeModuleCodes],
  );

  // Ottiene un modulo per codice
  const getModule = useCallback(
    (code: string): ModuleDto | undefined => {
      return modules.find((m) => m.code === code);
    },
    [modules],
  );

  // Attiva un modulo
  const enableModule = useCallback(
    async (
      code: string,
      request: EnableModuleRequest,
    ): Promise<SubscriptionDto> => {
      const subscription = await moduleService.enable(code, request);
      // Invalida le query per ricaricare i dati
      await queryClient.invalidateQueries({ queryKey: ["modules"] });
      return subscription;
    },
    [queryClient],
  );

  // Disattiva un modulo
  const disableModule = useCallback(
    async (code: string): Promise<void> => {
      await moduleService.disable(code);
      // Invalida le query per ricaricare i dati
      await queryClient.invalidateQueries({ queryKey: ["modules"] });
    },
    [queryClient],
  );

  // Ricarica i dati dei moduli
  const refreshModules = useCallback(async (): Promise<void> => {
    await queryClient.invalidateQueries({ queryKey: ["modules"] });
  }, [queryClient]);

  const value: ModuleContextValue = {
    modules,
    activeModules,
    activeModuleCodes,
    isLoading: isLoadingModules || isLoadingActive,
    error: modulesError || activeError,
    isModuleEnabled,
    getModule,
    enableModule,
    disableModule,
    refreshModules,
  };

  return (
    <ModuleContext.Provider value={value}>{children}</ModuleContext.Provider>
  );
}

// ==================== HOOKS ====================

/**
 * Hook per accedere al context dei moduli
 */
export function useModules(): ModuleContextValue {
  const context = useContext(ModuleContext);
  if (!context) {
    throw new Error("useModules must be used within a ModuleProvider");
  }
  return context;
}

/**
 * Hook per verificare se un singolo modulo è abilitato
 */
export function useModuleEnabled(code: string): boolean {
  const { isModuleEnabled } = useModules();
  return isModuleEnabled(code);
}

/**
 * Hook per ottenere solo i moduli attivi
 */
export function useActiveModules(): ModuleDto[] {
  const { activeModules } = useModules();
  return activeModules;
}

/**
 * Hook per ottenere i codici dei moduli attivi
 */
export function useActiveModuleCodes(): string[] {
  const { activeModuleCodes } = useModules();
  return activeModuleCodes;
}

/**
 * Hook per ottenere un modulo specifico
 */
export function useModule(code: string): ModuleDto | undefined {
  const { getModule } = useModules();
  return getModule(code);
}
