/**
 * useUserMandates Hook
 * 
 * Hook for managing user-mandate memberships (which users belong to which mandates with which roles).
 * Uses the /api/mandates/{mandateId}/users 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 MandateUser {
  id: string;  // UserMandate ID as primary key
  userId: string;
  username: string;
  email: string | null;
  firstname: string | null;
  lastname: string | null;
  roleIds: string[];
  enabled: boolean;
}

export interface UserMandateCreate {
  targetUserId: string;
  roleIds: string[];
}

export interface UserMandateResponse {
  id: string;  // UserMandate ID as primary key
  userId: string;
  mandateId: string;
  roleIds: string[];
  enabled: boolean;
}

export interface Role {
  id: string;
  roleLabel: string;
  description?: string | { [key: string]: string };
  mandateId?: string;
  featureInstanceId?: string;
  isSystemRole?: boolean;
}

export interface Mandate {
  id: string;
  name: string | { [key: string]: string };
  code?: string;
  language?: string;
}

/**
 * Hook for managing user-mandate memberships
 */
export function useUserMandates() {
  const [users, setUsers] = useState<MandateUser[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [pagination, setPagination] = useState<PaginationMetadata | null>(null);
  
  // Store current mandate for refetch
  const currentMandateIdRef = useRef<string>('');

  /**
   * Fetch all users in a specific mandate with optional pagination
   */
  const fetchMandateUsers = useCallback(async (
    mandateIdOrPagination?: string | PaginationParams
  ): Promise<MandateUser[]> => {
    setLoading(true);
    setError(null);
    
    let mandateId: string;
    let paginationParams: PaginationParams = {};
    
    // Handle backward compatibility
    if (typeof mandateIdOrPagination === 'string') {
      mandateId = mandateIdOrPagination;
      currentMandateIdRef.current = mandateId;
    } else if (mandateIdOrPagination && typeof mandateIdOrPagination === 'object') {
      paginationParams = mandateIdOrPagination;
      mandateId = currentMandateIdRef.current;
    } else {
      mandateId = currentMandateIdRef.current;
    }
    
    if (!mandateId) {
      setLoading(false);
      return [];
    }
    
    try {
      const params = new URLSearchParams();
      if (Object.keys(paginationParams).length > 0) {
        params.append('pagination', JSON.stringify(paginationParams));
      }
      
      const url = params.toString() 
        ? `/api/mandates/${mandateId}/users?${params.toString()}`
        : `/api/mandates/${mandateId}/users`;
      
      const response = await api.get(url);
      
      let data: MandateUser[] = [];
      if (response.data?.items && Array.isArray(response.data.items)) {
        data = response.data.items;
        if (response.data.pagination) {
          setPagination(response.data.pagination);
        }
      } else {
        data = Array.isArray(response.data) ? response.data : [];
      }
      
      setUsers(data);
      return data;
    } catch (err: any) {
      const errorMessage = err.response?.data?.detail || err.message || 'Failed to fetch mandate users';
      setError(errorMessage);
      setUsers([]);
      setPagination(null);
      return [];
    } finally {
      setLoading(false);
    }
  }, []);

  /**
   * Add a user to a mandate with specified roles
   */
  const addUserToMandate = useCallback(async (
    mandateId: string,
    data: UserMandateCreate
  ): Promise<{ success: boolean; data?: UserMandateResponse; error?: string }> => {
    setLoading(true);
    setError(null);
    try {
      const response = await api.post(`/api/mandates/${mandateId}/users`, data);
      return { success: true, data: response.data };
    } catch (err: any) {
      const errorMessage = err.response?.data?.detail || err.message || 'Failed to add user to mandate';
      setError(errorMessage);
      return { success: false, error: errorMessage };
    } finally {
      setLoading(false);
    }
  }, []);

  /**
   * Remove a user from a mandate
   */
  const removeUserFromMandate = useCallback(async (
    mandateId: string,
    userId: string
  ): Promise<{ success: boolean; error?: string }> => {
    setLoading(true);
    setError(null);
    try {
      await api.delete(`/api/mandates/${mandateId}/users/${userId}`);
      // Optimistically update the local state
      setUsers(prev => prev.filter(u => u.userId !== userId));
      return { success: true };
    } catch (err: any) {
      const errorMessage = err.response?.data?.detail || err.message || 'Failed to remove user from mandate';
      setError(errorMessage);
      return { success: false, error: errorMessage };
    } finally {
      setLoading(false);
    }
  }, []);

  /**
   * Update a user's roles within a mandate
   */
  const updateUserRoles = useCallback(async (
    mandateId: string,
    userId: string,
    roleIds: string[]
  ): Promise<{ success: boolean; data?: UserMandateResponse; error?: string }> => {
    setLoading(true);
    setError(null);
    try {
      const response = await api.put(`/api/mandates/${mandateId}/users/${userId}/roles`, roleIds);
      // Optimistically update the local state
      setUsers(prev => prev.map(u => 
        u.userId === userId ? { ...u, roleIds } : u
      ));
      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);
    }
  }, []);

  /**
   * Fetch all available mandates (for selection)
   */
  const fetchMandates = useCallback(async (): Promise<Mandate[]> => {
    try {
      const response = await api.get('/api/mandates/');
      if (response.data?.items && Array.isArray(response.data.items)) {
        return response.data.items;
      }
      return Array.isArray(response.data) ? response.data : [];
    } catch (err: any) {
      console.error('Error fetching mandates:', err);
      return [];
    }
  }, []);

  /**
   * Fetch all available roles (global and mandate-specific)
   */
  const fetchRoles = useCallback(async (mandateId?: string): Promise<Role[]> => {
    try {
      const response = await api.get('/api/rbac/roles');
      let roles: Role[] = [];
      if (response.data?.items && Array.isArray(response.data.items)) {
        roles = response.data.items;
      } else if (Array.isArray(response.data)) {
        roles = response.data;
      }
      
      // Filter to global roles and roles for this mandate
      if (mandateId) {
        return roles.filter(r => 
          !r.mandateId || r.mandateId === mandateId
        );
      }
      return roles;
    } catch (err: any) {
      console.error('Error fetching roles:', err);
      return [];
    }
  }, []);

  /**
   * Fetch all users (for selection when adding to mandate)
   */
  const fetchAllUsers = useCallback(async (): Promise<Array<{id: string; username: string; email?: string; fullName?: string}>> => {
    try {
      const response = await api.get('/api/users/');
      if (response.data?.items && Array.isArray(response.data.items)) {
        return response.data.items;
      }
      return Array.isArray(response.data) ? response.data : [];
    } catch (err: any) {
      console.error('Error fetching users:', err);
      return [];
    }
  }, []);

  return {
    users,
    loading,
    error,
    pagination,
    fetchMandateUsers,
    addUserToMandate,
    removeUserFromMandate,
    updateUserRoles,
    fetchMandates,
    fetchRoles,
    fetchAllUsers,
  };
}

export default useUserMandates;
