import { createContext, useContext, useState, useEffect, useCallback } from 'react';
import type { ReactNode } from 'react';
import { settingsAPI } from '../api/client';
import { useAuth } from './AuthContext';
import type { UserPermissions } from '../types';

// User-facing modules that can be toggled
export const TOGGLEABLE_MODULES = [
  { id: 'feature1', icon: 'playlist_play', defaultEnabled: true, defaultPosition: 'top' as const },
  { id: 'feature2', icon: 'download', defaultEnabled: true, defaultPosition: 'top' as const },
  { id: 'feature3', icon: 'cast', defaultEnabled: true, defaultPosition: 'top' as const },
  { id: 'search', icon: 'search', defaultEnabled: true, defaultPosition: 'bottom' as const },
  { id: 'notifications', icon: 'notifications', defaultEnabled: true, defaultPosition: 'bottom' as const },
] as const;

export type ModuleId = typeof TOGGLEABLE_MODULES[number]['id'];
export type ModulePosition = 'top' | 'bottom';

export interface ModuleState {
  admin: boolean;
  user: boolean;
  position: ModulePosition;
}

// Default order for modules (top modules, then bottom modules)
const DEFAULT_MODULE_ORDER: string[] = ['feature1', 'feature2', 'feature3', 'search', 'notifications'];

interface ModulesContextType {
  moduleStates: Record<ModuleId, ModuleState>;
  moduleOrder: string[];
  isModuleEnabled: (moduleId: string) => boolean;
  isModuleEnabledForUser: (moduleId: string, userPermissions: UserPermissions | undefined, isSuperuser: boolean) => boolean;
  setModuleEnabled: (moduleId: ModuleId, type: 'admin' | 'user', enabled: boolean) => void;
  setModulePosition: (moduleId: ModuleId, position: ModulePosition) => void;
  setModuleOrder: (order: string[]) => void;
  saveModulesToBackend: () => Promise<void>;
  saveModuleOrder: (order: string[]) => Promise<void>;
  isLoading: boolean;
  hasInitialized: boolean;
}

const ModulesContext = createContext<ModulesContextType | undefined>(undefined);

// Default states
const getDefaultStates = (): Record<ModuleId, ModuleState> => {
  const states: Record<string, ModuleState> = {};
  TOGGLEABLE_MODULES.forEach(m => {
    states[m.id] = { admin: m.defaultEnabled, user: m.defaultEnabled, position: m.defaultPosition };
  });
  return states as Record<ModuleId, ModuleState>;
};

export function ModulesProvider({ children }: { children: ReactNode }) {
  const { token } = useAuth();
  const [moduleStates, setModuleStates] = useState<Record<ModuleId, ModuleState>>(getDefaultStates);
  const [moduleOrder, setModuleOrderState] = useState<string[]>(DEFAULT_MODULE_ORDER);
  const [isLoading, setIsLoading] = useState(true);
  const [hasInitialized, setHasInitialized] = useState(false);

  // Load module settings from backend
  const loadModulesFromBackend = useCallback(async () => {
    try {
      const settings = await settingsAPI.getModules();
      const newStates = { ...getDefaultStates() };

      // Helper to safely parse boolean
      const parseBool = (val: any, defaultVal: boolean): boolean => {
        if (val === undefined || val === null) return defaultVal;
        if (val === true || val === 'true' || val === 1 || val === '1') return true;
        if (val === false || val === 'false' || val === 0 || val === '0') return false;
        return defaultVal;
      };

      TOGGLEABLE_MODULES.forEach(m => {
        const adminKey = `module_${m.id}_admin_enabled`;
        const userKey = `module_${m.id}_user_enabled`;
        const positionKey = `module_${m.id}_position`;

        // Check for new keys
        // If key exists in settings, use it (parsed). If not, use defaultEnabled.
        // Crucially, if settings[key] is present, we MUST use it, even if it parses to false.
        if (settings[adminKey] !== undefined) {
          newStates[m.id].admin = parseBool(settings[adminKey], m.defaultEnabled);
        } else {
          newStates[m.id].admin = m.defaultEnabled;
        }

        if (settings[userKey] !== undefined) {
          newStates[m.id].user = parseBool(settings[userKey], m.defaultEnabled);
        } else {
          newStates[m.id].user = m.defaultEnabled;
        }

        // Load position
        if (settings[positionKey] !== undefined) {
          newStates[m.id].position = settings[positionKey] === 'bottom' ? 'bottom' : 'top';
        } else {
          newStates[m.id].position = m.defaultPosition;
        }

        // Fallback for backward compatibility (if old key exists)
        const oldKey = `module_${m.id}_enabled`;
        if (settings[oldKey] !== undefined && settings[adminKey] === undefined) {
          const val = parseBool(settings[oldKey], m.defaultEnabled);
          newStates[m.id].admin = val;
          newStates[m.id].user = val;
        }
      });

      setModuleStates(newStates);

      // Load module order
      if (settings.modules_order) {
        let order: string[];
        if (typeof settings.modules_order === 'string') {
          try {
            order = JSON.parse(settings.modules_order);
          } catch {
            order = DEFAULT_MODULE_ORDER;
          }
        } else if (Array.isArray(settings.modules_order)) {
          order = settings.modules_order;
        } else {
          order = DEFAULT_MODULE_ORDER;
        }
        // Ensure all toggleable modules are included (for newly added modules)
        const allModuleIds = TOGGLEABLE_MODULES.map(m => m.id);
        const missingModules = allModuleIds.filter(id => !order.includes(id));
        if (missingModules.length > 0) {
          order = [...order, ...missingModules];
        }
        setModuleOrderState(order);
      }

      setHasInitialized(true);
    } catch (error) {
      console.error('Failed to load modules from backend:', error);
      setHasInitialized(true); // Even on error, mark as initialized to prevent saving defaults
    } finally {
      setIsLoading(false);
    }
  }, []);

  // Save module settings to backend
  const saveModulesToBackend = useCallback(async () => {
    try {
      const data: Record<string, boolean | string> = {};
      TOGGLEABLE_MODULES.forEach(m => {
        data[`module_${m.id}_admin_enabled`] = moduleStates[m.id].admin;
        data[`module_${m.id}_user_enabled`] = moduleStates[m.id].user;
        data[`module_${m.id}_position`] = moduleStates[m.id].position;
      });
      await settingsAPI.updateModules(data);
    } catch (error) {
      console.error('Failed to save modules to backend:', error);
      throw error;
    }
  }, [moduleStates]);

  // Save module order to backend
  const saveModuleOrder = useCallback(async (order: string[]) => {
    try {
      await settingsAPI.updateModules({ modules_order: order });
    } catch (error) {
      console.error('Failed to save module order to backend:', error);
      throw error;
    }
  }, []);

  // Set module order (local state only, call saveModuleOrder to persist)
  const setModuleOrder = useCallback((order: string[]) => {
    setModuleOrderState(order);
  }, []);

  // Load modules when token becomes available
  useEffect(() => {
    if (token) {
      setIsLoading(true);
      setHasInitialized(false);
      loadModulesFromBackend();
    } else {
      setModuleStates(getDefaultStates());
      setIsLoading(false);
      setHasInitialized(true); // No token, mark as initialized
    }
  }, [token, loadModulesFromBackend]);

  const isModuleEnabled = useCallback((moduleId: string): boolean => {
    // Dashboard is always enabled
    if (moduleId === 'dashboard') return true;
    // Admin modules are always enabled for admins
    if (moduleId === 'users' || moduleId === 'settings') return true;

    const state = moduleStates[moduleId as ModuleId];
    return state ? state.admin : true;
  }, [moduleStates]);

  // Check if module is enabled for a specific user (considering global state + user permissions)
  const isModuleEnabledForUser = useCallback((
    moduleId: string,
    userPermissions: UserPermissions | undefined,
    isSuperuser: boolean
  ): boolean => {
    // Dashboard is always enabled
    if (moduleId === 'dashboard') return true;
    // Admin modules are always enabled for admins
    if (moduleId === 'users' || moduleId === 'settings') return true;

    const state = moduleStates[moduleId as ModuleId];
    if (!state) return true;

    // 1. If disabled for admin, it's disabled for everyone
    if (!state.admin) return false;

    // 2. If superuser, they have access (since admin is enabled)
    if (isSuperuser) return true;

    // 3. If disabled for users globally, regular users can't access
    if (!state.user) return false;

    // 4. Check user-specific permissions
    if (userPermissions && userPermissions[moduleId] !== undefined) {
      return userPermissions[moduleId];
    }

    // Default: enabled
    return true;
  }, [moduleStates]);

  const setModuleEnabled = useCallback((moduleId: ModuleId, type: 'admin' | 'user', enabled: boolean) => {
    setModuleStates(prev => {
      const newState = { ...prev };
      newState[moduleId] = { ...newState[moduleId], [type]: enabled };

      // If admin is disabled, user must be disabled too
      if (type === 'admin' && !enabled) {
        newState[moduleId].user = false;
      }

      return newState;
    });
  }, []);

  const setModulePosition = useCallback((moduleId: ModuleId, position: ModulePosition) => {
    setModuleStates(prev => {
      const newState = { ...prev };
      newState[moduleId] = { ...newState[moduleId], position };
      return newState;
    });
  }, []);

  return (
    <ModulesContext.Provider
      value={{
        moduleStates,
        moduleOrder,
        isModuleEnabled,
        isModuleEnabledForUser,
        setModuleEnabled,
        setModulePosition,
        setModuleOrder,
        saveModulesToBackend,
        saveModuleOrder,
        isLoading,
        hasInitialized,
      }}
    >
      {children}
    </ModulesContext.Provider>
  );
}

export function useModules() {
  const context = useContext(ModulesContext);
  if (context === undefined) {
    throw new Error('useModules must be used within a ModulesProvider');
  }
  return context;
}
