/**
 * useInvitations Hook
 * 
 * Hook for managing invitations (creating, listing, validating, accepting).
 * Uses the /api/invitations 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 Invitation {
  id: string;
  token: string;
  mandateId: string;
  featureInstanceId?: string;
  roleIds: string[];
  targetUsername: string;
  email?: string;
  createdBy: string;
  createdAt: number;
  expiresAt: number;
  usedBy?: string;
  usedAt?: number;
  revokedAt?: number;
  maxUses: number;
  currentUses: number;
  inviteUrl: string;
  emailSent?: boolean;
  isExpired?: boolean;
  isUsedUp?: boolean;
}

export interface InvitationCreate {
  targetUsername: string;
  email?: string;
  roleIds: string[];
  featureInstanceId?: string;
  expiresInHours?: number;
  maxUses?: number;
}

export interface InvitationValidation {
  valid: boolean;
  reason?: string;
  mandateId?: string;
  mandateName?: string;
  featureInstanceId?: string;
  roleIds: string[];
  roleLabels?: string[];
  targetUsername?: string;
}


/**
 * Hook for managing invitations
 */
export function useInvitations() {
  const [invitations, setInvitations] = useState<Invitation[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [pagination, setPagination] = useState<PaginationMetadata | null>(null);
  
  // Store current context for refetch
  const currentMandateIdRef = useRef<string>('');
  const currentOptionsRef = useRef<{ includeUsed?: boolean; includeExpired?: boolean }>({});

  /**
   * Fetch all invitations for a mandate with optional pagination
   */
  const fetchInvitations = useCallback(async (
    mandateIdOrPagination?: string | PaginationParams,
    options?: { includeUsed?: boolean; includeExpired?: boolean }
  ): Promise<Invitation[]> => {
    setLoading(true);
    setError(null);
    
    let mandateId: string;
    let paginationParams: PaginationParams = {};
    
    // Handle backward compatibility
    if (typeof mandateIdOrPagination === 'string') {
      mandateId = mandateIdOrPagination;
      currentMandateIdRef.current = mandateId;
      if (options) {
        currentOptionsRef.current = options;
      }
    } else if (mandateIdOrPagination && typeof mandateIdOrPagination === 'object') {
      // Called with pagination params only (refetch from FormGeneratorTable)
      paginationParams = mandateIdOrPagination;
      mandateId = currentMandateIdRef.current;
    } else {
      mandateId = currentMandateIdRef.current;
    }
    
    if (!mandateId) {
      setLoading(false);
      return [];
    }
    
    const fetchOptions = options || currentOptionsRef.current;
    
    try {
      const params = new URLSearchParams();
      if (fetchOptions?.includeUsed) params.append('includeUsed', 'true');
      if (fetchOptions?.includeExpired) params.append('includeExpired', 'true');
      if (Object.keys(paginationParams).length > 0) {
        params.append('pagination', JSON.stringify(paginationParams));
      }
      
      const response = await api.get(`/api/invitations/?${params.toString()}`, {
        headers: { 'X-Mandate-Id': mandateId }
      });
      
      let data: Invitation[] = [];
      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 : [];
      }
      
      setInvitations(data);
      return data;
    } catch (err: any) {
      const errorMessage = err.response?.data?.detail || err.message || 'Failed to fetch invitations';
      setError(errorMessage);
      setInvitations([]);
      setPagination(null);
      return [];
    } finally {
      setLoading(false);
    }
  }, []);

  /**
   * Create a new invitation
   */
  const createInvitation = useCallback(async (
    mandateId: string,
    data: InvitationCreate
  ): Promise<{ success: boolean; data?: Invitation; error?: string }> => {
    setLoading(true);
    setError(null);
    try {
      const response = await api.post('/api/invitations/', 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 invitation';
      setError(errorMessage);
      return { success: false, error: errorMessage };
    } finally {
      setLoading(false);
    }
  }, []);

  /**
   * Revoke an invitation
   */
  const revokeInvitation = useCallback(async (
    mandateId: string,
    invitationId: string
  ): Promise<{ success: boolean; error?: string }> => {
    setLoading(true);
    setError(null);
    try {
      await api.delete(`/api/invitations/${invitationId}`, {
        headers: { 'X-Mandate-Id': mandateId }
      });
      // Optimistically update local state
      setInvitations(prev => prev.filter(inv => inv.id !== invitationId));
      return { success: true };
    } catch (err: any) {
      const errorMessage = err.response?.data?.detail || err.message || 'Failed to revoke invitation';
      setError(errorMessage);
      return { success: false, error: errorMessage };
    } finally {
      setLoading(false);
    }
  }, []);

  /**
   * Validate an invitation token (public - no auth required)
   */
  const validateInvitation = useCallback(async (
    token: string
  ): Promise<InvitationValidation> => {
    setLoading(true);
    setError(null);
    try {
      const response = await api.get(`/api/invitations/validate/${token}`);
      return response.data;
    } catch (err: any) {
      const errorMessage = err.response?.data?.detail || err.message || 'Failed to validate invitation';
      setError(errorMessage);
      return {
        valid: false,
        reason: errorMessage,
        roleIds: []
      };
    } finally {
      setLoading(false);
    }
  }, []);

  /**
   * Accept an invitation (requires authentication)
   */
  const acceptInvitation = useCallback(async (
    token: string
  ): Promise<{ success: boolean; data?: any; error?: string }> => {
    setLoading(true);
    setError(null);
    try {
      const response = await api.post(`/api/invitations/accept/${token}`);
      return { success: true, data: response.data };
    } catch (err: any) {
      const errorMessage = err.response?.data?.detail || err.message || 'Failed to accept invitation';
      setError(errorMessage);
      return { success: false, error: errorMessage };
    } finally {
      setLoading(false);
    }
  }, []);

  return {
    invitations,
    loading,
    error,
    pagination,
    fetchInvitations,
    createInvitation,
    revokeInvitation,
    validateInvitation,
    acceptInvitation,
  };
}

export default useInvitations;
