/**
 * useFeatureAccess Hook
 * 
 * Hook for managing feature instance access (which users can access which feature instances with which roles).
 * Uses the /api/features endpoints.
 */

import { useState, useCallback, useRef } from 'react';
import api from '../api';

// Types
export interface PaginationParams {
  page?: number;
  pageSize?: number;
  search?: string;
  filters?: Record<string, any>;
  sort?: Array<{ field: string; direction: 'asc' | 'desc' }>;
}

export interface PaginationMetadata {
  currentPage: number;
  pageSize: number;
  totalItems: number;
  totalPages: number;
}

export interface Feature {
  code: string;
  label: string | { [key: string]: string };
  icon?: string;
  enabled?: boolean;
}

export interface FeatureInstance {
  id: string;
  featureCode: string;
  mandateId: string;
  label: string;
  enabled: boolean;
}

export interface FeatureAccess {
  id: string;
  userId: string;
  featureInstanceId: string;
  enabled: boolean;
  roleIds?: string[];
}

export interface FeatureAccessUser {
  id: string;  // FeatureAccess ID as primary key
  userId: string;
  username: string;
  email?: string;
  fullName?: string;
  roleIds: string[];
  roleLabels: string[];
  enabled: boolean;
}

export interface FeatureInstanceRole {
  id: string;
  roleLabel: string;
  description?: { [key: string]: string };
  featureCode?: string;
  isSystemRole?: boolean;
}

export interface AddUserToInstanceRequest {
  userId: string;
  roleIds: string[];
}

export interface FeatureInstanceCreate {
  featureCode: string;
  label: string;
  enabled?: boolean;
  copyTemplateRoles?: boolean;
}

/**
 * Hook for managing feature access
 */
export function useFeatureAccess() {
  const [features, setFeatures] = useState<Feature[]>([]);
  const [instances, setInstances] = useState<FeatureInstance[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [instancesPagination, setInstancesPagination] = useState<PaginationMetadata | null>(null);
  
  // Store current context for refetch
  const currentMandateIdRef = useRef<string>('');
  const currentFeatureCodeRef = useRef<string | undefined>(undefined);

  /**
   * Fetch all available features
   */
  const fetchFeatures = useCallback(async (): Promise<Feature[]> => {
    setLoading(true);
    setError(null);
    try {
      const response = await api.get('/api/features/');
      const data = Array.isArray(response.data) ? response.data : [];
      setFeatures(data);
      return data;
    } catch (err: any) {
      const errorMessage = err.response?.data?.detail || err.message || 'Failed to fetch features';
      setError(errorMessage);
      setFeatures([]);
      return [];
    } finally {
      setLoading(false);
    }
  }, []);

  /**
   * Fetch feature instances for a mandate with optional pagination
   */
  const fetchInstances = useCallback(async (
    mandateIdOrPagination?: string | PaginationParams,
    featureCode?: string
  ): Promise<FeatureInstance[]> => {
    setLoading(true);
    setError(null);
    
    let mandateId: string;
    let paginationParams: PaginationParams = {};
    
    // Handle backward compatibility
    if (typeof mandateIdOrPagination === 'string') {
      mandateId = mandateIdOrPagination;
      currentMandateIdRef.current = mandateId;
      currentFeatureCodeRef.current = featureCode;
    } else if (mandateIdOrPagination && typeof mandateIdOrPagination === 'object') {
      paginationParams = mandateIdOrPagination;
      mandateId = currentMandateIdRef.current;
      featureCode = currentFeatureCodeRef.current;
    } else {
      mandateId = currentMandateIdRef.current;
      featureCode = currentFeatureCodeRef.current;
    }
    
    if (!mandateId) {
      setLoading(false);
      return [];
    }
    
    try {
      const params = new URLSearchParams();
      if (featureCode) {
        params.append('featureCode', featureCode);
      }
      if (Object.keys(paginationParams).length > 0) {
        params.append('pagination', JSON.stringify(paginationParams));
      }
      
      const url = params.toString() 
        ? `/api/features/instances?${params.toString()}`
        : '/api/features/instances';
      
      const response = await api.get(url, {
        headers: {
          'X-Mandate-Id': mandateId
        }
      });
      
      let data: FeatureInstance[] = [];
      if (response.data?.items && Array.isArray(response.data.items)) {
        data = response.data.items;
        if (response.data.pagination) {
          setInstancesPagination(response.data.pagination);
        }
      } else {
        data = Array.isArray(response.data) ? response.data : [];
      }
      
      setInstances(data);
      return data;
    } catch (err: any) {
      const errorMessage = err.response?.data?.detail || err.message || 'Failed to fetch feature instances';
      setError(errorMessage);
      setInstances([]);
      setInstancesPagination(null);
      return [];
    } finally {
      setLoading(false);
    }
  }, []);

  /**
   * Create a new feature instance
   */
  const createInstance = useCallback(async (
    mandateId: string,
    data: FeatureInstanceCreate
  ): Promise<{ success: boolean; data?: FeatureInstance; error?: string }> => {
    setLoading(true);
    setError(null);
    try {
      const response = await api.post('/api/features/instances', data, {
        headers: {
          'X-Mandate-Id': mandateId
        }
      });
      return { success: true, data: response.data };
    } catch (err: any) {
      const errorMessage = err.response?.data?.detail || err.message || 'Failed to create feature instance';
      setError(errorMessage);
      return { success: false, error: errorMessage };
    } finally {
      setLoading(false);
    }
  }, []);

  /**
   * Update a feature instance (label, enabled)
   */
  const updateInstance = useCallback(async (
    mandateId: string,
    instanceId: string,
    data: { label?: string; enabled?: boolean }
  ): Promise<{ success: boolean; data?: FeatureInstance; error?: string }> => {
    setLoading(true);
    setError(null);
    try {
      const response = await api.put(`/api/features/instances/${instanceId}`, data, {
        headers: {
          'X-Mandate-Id': mandateId
        }
      });
      // Update local state
      setInstances(prev => prev.map(i => i.id === instanceId ? { ...i, ...response.data } : i));
      return { success: true, data: response.data };
    } catch (err: any) {
      const errorMessage = err.response?.data?.detail || err.message || 'Failed to update feature instance';
      setError(errorMessage);
      return { success: false, error: errorMessage };
    } finally {
      setLoading(false);
    }
  }, []);

  /**
   * Delete a feature instance
   */
  const deleteInstance = useCallback(async (
    mandateId: string,
    instanceId: string
  ): Promise<{ success: boolean; error?: string }> => {
    setLoading(true);
    setError(null);
    try {
      await api.delete(`/api/features/instances/${instanceId}`, {
        headers: {
          'X-Mandate-Id': mandateId
        }
      });
      // Optimistically update the local state
      setInstances(prev => prev.filter(i => i.id !== instanceId));
      return { success: true };
    } catch (err: any) {
      const errorMessage = err.response?.data?.detail || err.message || 'Failed to delete feature instance';
      setError(errorMessage);
      return { success: false, error: errorMessage };
    } finally {
      setLoading(false);
    }
  }, []);

  /**
   * Sync roles for a feature instance from templates
   */
  const syncInstanceRoles = useCallback(async (
    mandateId: string,
    instanceId: string,
    addOnly: boolean = true
  ): Promise<{ success: boolean; data?: { added: number; removed: number; unchanged: number }; error?: string }> => {
    setLoading(true);
    setError(null);
    try {
      const response = await api.post(`/api/features/instances/${instanceId}/sync-roles?addOnly=${addOnly}`, {}, {
        headers: {
          'X-Mandate-Id': mandateId
        }
      });
      return { success: true, data: response.data };
    } catch (err: any) {
      const errorMessage = err.response?.data?.detail || err.message || 'Failed to sync instance roles';
      setError(errorMessage);
      return { success: false, error: errorMessage };
    } finally {
      setLoading(false);
    }
  }, []);

  /**
   * Get current user's feature instances (grouped by mandate)
   */
  const fetchMyFeatureInstances = useCallback(async (): Promise<{
    mandates: Array<{
      id: string;
      name: string;
      features: Array<{
        code: string;
        label: string | { [key: string]: string };
        instances: Array<{
          id: string;
          featureCode: string;
          mandateId: string;
          instanceLabel: string;
        }>;
      }>;
    }>;
  }> => {
    try {
      const response = await api.get('/api/features/my');
      return response.data || { mandates: [] };
    } catch (err: any) {
      console.error('Error fetching my feature instances:', err);
      return { mandates: [] };
    }
  }, []);

  /**
   * Get template roles for features
   */
  const fetchTemplateRoles = useCallback(async (featureCode?: string): Promise<any[]> => {
    try {
      let url = '/api/features/templates/roles';
      if (featureCode) {
        url += `?featureCode=${encodeURIComponent(featureCode)}`;
      }
      const response = await api.get(url);
      return Array.isArray(response.data) ? response.data : [];
    } catch (err: any) {
      console.error('Error fetching template roles:', err);
      return [];
    }
  }, []);

  // ============================================
  // Feature Instance Users Management
  // ============================================

  /**
   * Fetch all users with access to a specific feature instance
   */
  const fetchInstanceUsers = useCallback(async (
    mandateId: string,
    instanceId: string
  ): Promise<FeatureAccessUser[]> => {
    setLoading(true);
    setError(null);
    try {
      const response = await api.get(`/api/features/instances/${instanceId}/users`, {
        headers: {
          'X-Mandate-Id': mandateId
        }
      });
      return Array.isArray(response.data) ? response.data : [];
    } catch (err: any) {
      const errorMessage = err.response?.data?.detail || err.message || 'Failed to fetch instance users';
      setError(errorMessage);
      return [];
    } finally {
      setLoading(false);
    }
  }, []);

  /**
   * Add a user to a feature instance with specified roles
   */
  const addUserToInstance = useCallback(async (
    mandateId: string,
    instanceId: string,
    data: AddUserToInstanceRequest
  ): Promise<{ success: boolean; data?: any; error?: string }> => {
    setLoading(true);
    setError(null);
    try {
      const response = await api.post(`/api/features/instances/${instanceId}/users`, data, {
        headers: {
          'X-Mandate-Id': mandateId
        }
      });
      return { success: true, data: response.data };
    } catch (err: any) {
      const errorMessage = err.response?.data?.detail || err.message || 'Failed to add user to instance';
      setError(errorMessage);
      return { success: false, error: errorMessage };
    } finally {
      setLoading(false);
    }
  }, []);

  /**
   * Remove a user's access from a feature instance
   */
  const removeUserFromInstance = useCallback(async (
    mandateId: string,
    instanceId: string,
    userId: string
  ): Promise<{ success: boolean; error?: string }> => {
    setLoading(true);
    setError(null);
    try {
      await api.delete(`/api/features/instances/${instanceId}/users/${userId}`, {
        headers: {
          'X-Mandate-Id': mandateId
        }
      });
      return { success: true };
    } catch (err: any) {
      const errorMessage = err.response?.data?.detail || err.message || 'Failed to remove user from instance';
      setError(errorMessage);
      return { success: false, error: errorMessage };
    } finally {
      setLoading(false);
    }
  }, []);

  /**
   * Update a user's roles in a feature instance
   */
  const updateInstanceUserRoles = useCallback(async (
    mandateId: string,
    instanceId: string,
    userId: string,
    roleIds: string[]
  ): Promise<{ success: boolean; data?: any; error?: string }> => {
    setLoading(true);
    setError(null);
    try {
      const response = await api.put(
        `/api/features/instances/${instanceId}/users/${userId}/roles`,
        roleIds,
        {
          headers: {
            'X-Mandate-Id': mandateId
          }
        }
      );
      return { success: true, data: response.data };
    } catch (err: any) {
      const errorMessage = err.response?.data?.detail || err.message || 'Failed to update user roles';
      setError(errorMessage);
      return { success: false, error: errorMessage };
    } finally {
      setLoading(false);
    }
  }, []);

  /**
   * Get available roles for a feature instance
   */
  const fetchInstanceRoles = useCallback(async (
    mandateId: string,
    instanceId: string
  ): Promise<FeatureInstanceRole[]> => {
    try {
      const response = await api.get(`/api/features/instances/${instanceId}/available-roles`, {
        headers: {
          'X-Mandate-Id': mandateId
        }
      });
      return Array.isArray(response.data) ? response.data : [];
    } catch (err: any) {
      console.error('Error fetching instance roles:', err);
      return [];
    }
  }, []);

  return {
    features,
    instances,
    instancesPagination,
    loading,
    error,
    fetchFeatures,
    fetchInstances,
    createInstance,
    updateInstance,
    deleteInstance,
    syncInstanceRoles,
    fetchMyFeatureInstances,
    fetchTemplateRoles,
    // Instance users management
    fetchInstanceUsers,
    addUserToInstance,
    removeUserFromInstance,
    updateInstanceUserRoles,
    fetchInstanceRoles,
  };
}

export default useFeatureAccess;
