import { useState, useCallback, useRef } from 'react';
import { useApiRequest } from './useApi';
import {
  fetchPermissions as fetchPermissionsApi,
  fetchAllPermissions as fetchAllPermissionsApi,
  type PermissionLevel,
  type UserPermissions,
  type PermissionContext
} from '../api/permissionApi';

// Re-export types for backward compatibility
export type { PermissionLevel, UserPermissions, PermissionContext };

// Permission cache interface
interface PermissionCache {
  [key: string]: UserPermissions;
}

// Operation type for permission checks
export type PermissionOperation = 'read' | 'create' | 'update' | 'delete';

// Default permission (no access)
const DEFAULT_NO_ACCESS: UserPermissions = {
  view: false,
  read: 'n' as PermissionLevel,
  create: 'n' as PermissionLevel,
  update: 'n' as PermissionLevel,
  delete: 'n' as PermissionLevel,
};

/**
 * Hook for managing RBAC permissions
 * Provides centralized permission checking with caching
 * 
 * Optimized to fetch all UI permissions in a single API call on first use,
 * then serve subsequent requests from cache.
 */
export const usePermissions = () => {
  const [loading, setLoading] = useState(false);
  const cacheRef = useRef<PermissionCache>({});
  const bulkLoadPromiseRef = useRef<Promise<void> | null>(null);
  const bulkLoadedContextsRef = useRef<Set<string>>(new Set());
  const pendingRequests = useRef<Map<string, Promise<UserPermissions>>>(new Map());
  const { request } = useApiRequest();

  /**
   * Generate a cache key for a permission check
   */
  const getPermissionKey = (context: PermissionContext, item?: string): string => {
    return `${context}:${item || 'null'}`;
  };

  /**
   * Load all permissions for a context (UI or RESOURCE) in bulk
   * This is called once per context and caches all permissions
   */
  const loadBulkPermissions = useCallback(async (context: 'UI' | 'RESOURCE'): Promise<void> => {
    // Skip if already loaded for this context
    if (bulkLoadedContextsRef.current.has(context)) {
      return;
    }

    // Check if there's already a pending bulk load
    if (bulkLoadPromiseRef.current) {
      await bulkLoadPromiseRef.current;
      return;
    }

    // Create the bulk load promise
    bulkLoadPromiseRef.current = (async () => {
      setLoading(true);
      try {
        console.log(`🔐 usePermissions: Bulk loading all ${context} permissions...`);
        const response = await fetchAllPermissionsApi(request, context);
        
        // Cache all permissions from the response
        const contextKey = context.toLowerCase() as 'ui' | 'resource';
        const permissions = response[contextKey] || {};
        
        const newCache: PermissionCache = { ...cacheRef.current };
        let count = 0;
        
        for (const [item, perm] of Object.entries(permissions)) {
          const key = getPermissionKey(context, item);
          newCache[key] = perm;
          count++;
        }
        
        cacheRef.current = newCache;
        bulkLoadedContextsRef.current.add(context);
        
        console.log(`✅ usePermissions: Bulk loaded ${count} ${context} permissions`);
      } catch (error: any) {
        console.error(`❌ usePermissions: Error bulk loading ${context} permissions:`, error);
        // Don't mark as loaded on error - allow retry
      } finally {
        bulkLoadPromiseRef.current = null;
        setLoading(false);
      }
    })();

    await bulkLoadPromiseRef.current;
  }, [request]);

  /**
   * Fetch individual permission (used for DATA context and fallback)
   */
  const fetchIndividualPermission = useCallback(async (
    context: PermissionContext,
    item?: string
  ): Promise<UserPermissions> => {
    const key = getPermissionKey(context, item);

    // Check cache first
    if (cacheRef.current[key]) {
      return cacheRef.current[key];
    }

    // Check if there's already a pending request for this key
    if (pendingRequests.current.has(key)) {
      return pendingRequests.current.get(key)!;
    }

    // Fetch individual permission
    const requestPromise = (async () => {
      setLoading(true);
      try {
        const permissions = await fetchPermissionsApi(request, context, item);
        
        // Update cache
        cacheRef.current = { ...cacheRef.current, [key]: permissions };
        
        return permissions;
      } catch (error: any) {
        console.error('Error checking permissions:', error);
        
        // Return cached value if available, otherwise default (no access)
        return cacheRef.current[key] || DEFAULT_NO_ACCESS;
      } finally {
        pendingRequests.current.delete(key);
        setLoading(false);
      }
    })();

    // Store pending request to prevent duplicates
    pendingRequests.current.set(key, requestPromise);

    return requestPromise;
  }, [request]);

  /**
   * Check permissions for a given context and item
   * Returns full UserPermissions object
   * 
   * For UI/RESOURCE contexts: Uses bulk-loaded cache, falls back to individual fetch
   * For DATA context: Fetches individually (as items are dynamic)
   */
  const checkPermission = useCallback(async (
    context: PermissionContext,
    item?: string
  ): Promise<UserPermissions> => {
    const key = getPermissionKey(context, item);

    // For UI and RESOURCE contexts, try bulk loading first
    if (context === 'UI' || context === 'RESOURCE') {
      // Ensure bulk permissions are loaded
      await loadBulkPermissions(context);
      
      // Check cache after bulk load
      if (cacheRef.current[key]) {
        return cacheRef.current[key];
      }
      
      // Check for global permission (_global key) - grants access to all items in this context
      const globalKey = getPermissionKey(context, '_global');
      if (cacheRef.current[globalKey]) {
        console.log(`✅ usePermissions: ${context}:${item} using global permission`);
        // Cache the global permission for this specific item too
        cacheRef.current[key] = cacheRef.current[globalKey];
        return cacheRef.current[globalKey];
      }
      
      // If not in bulk cache and no global permission, fall back to individual fetch
      // (item may not have explicit rule, but backend will calculate effective permissions)
      console.log(`⚠️ usePermissions: ${context}:${item} not in bulk cache, fetching individually`);
      return fetchIndividualPermission(context, item);
    }

    // For DATA context, fetch individually
    return fetchIndividualPermission(context, item);
  }, [loadBulkPermissions, fetchIndividualPermission]);

  /**
   * Check if user has permission for a specific operation
   * Returns true if user has any level of permission (not 'n')
   */
  const hasPermission = useCallback(async (
    context: PermissionContext,
    item: string,
    operation?: PermissionOperation
  ): Promise<boolean> => {
    const permissions = await checkPermission(context, item);

    if (!permissions.view) {
      return false;
    }

    if (context === 'DATA' && operation) {
      const level = permissions[operation];
      return level !== 'n';
    }

    return true;
  }, [checkPermission]);

  /**
   * Check if user can view a resource
   * Returns true if permissions.view is true
   */
  const canView = useCallback(async (
    context: PermissionContext,
    item: string
  ): Promise<boolean> => {
    const permissions = await checkPermission(context, item);
    return permissions.view === true;
  }, [checkPermission]);

  /**
   * Preload all permissions for UI context
   * Call this early in the app lifecycle to warm the cache
   */
  const preloadUiPermissions = useCallback(async (): Promise<void> => {
    await loadBulkPermissions('UI');
  }, [loadBulkPermissions]);

  /**
   * Clear the permission cache
   * Useful when user permissions change or after logout
   */
  const clearCache = useCallback(() => {
    cacheRef.current = {};
    bulkLoadedContextsRef.current.clear();
    pendingRequests.current.clear();
  }, []);

  return {
    checkPermission,
    hasPermission,
    canView,
    preloadUiPermissions,
    loading,
    clearCache,
  };
};

