/**
 * useAccessRules Hook
 * 
 * Hook for managing RBAC access rules for a role.
 * Supports both system admin (template roles) and feature admin (instance roles).
 */

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

// =============================================================================
// TYPES
// =============================================================================

export type RuleContext = 'DATA' | 'UI' | 'RESOURCE';
export type AccessLevel = 'n' | 'm' | 'g' | 'a' | null;

// =============================================================================
// ACCESS LEVEL LABELS
// =============================================================================

export const ACCESS_LEVEL_OPTIONS: { value: 'n' | 'm' | 'g' | 'a'; label: string; color: string }[] = [
  { value: 'n', label: 'Keine', color: '#e53e3e' },
  { value: 'm', label: 'Eigene', color: '#d69e2e' },
  { value: 'g', label: 'Gruppe', color: '#3182ce' },
  { value: 'a', label: 'Alle', color: '#38a169' },
];

export const getAccessLevelLabel = (level: AccessLevel | null): string => {
  if (!level) return '-';
  const option = ACCESS_LEVEL_OPTIONS.find(opt => opt.value === level);
  return option?.label || level;
};

export const getAccessLevelColor = (level: AccessLevel | null): string => {
  if (!level) return '#718096';
  const option = ACCESS_LEVEL_OPTIONS.find(opt => opt.value === level);
  return option?.color || '#718096';
};

export interface AccessRule {
  id: string;
  roleId: string;
  context: RuleContext;
  item: string | null;
  view: boolean;
  read: AccessLevel;
  create: AccessLevel;
  update: AccessLevel;
  delete: AccessLevel;
}

export interface AccessRuleCreate {
  context: RuleContext;
  item?: string | null;
  view?: boolean;
  read?: AccessLevel;
  create?: AccessLevel;
  update?: AccessLevel;
  delete?: AccessLevel;
}

interface GroupedRules {
  DATA: AccessRule[];
  UI: AccessRule[];
  RESOURCE: AccessRule[];
}

interface SaveResult {
  success: boolean;
  error?: string;
}

// =============================================================================
// HOOK
// =============================================================================

export function useAccessRules(roleId: string, apiBasePath: string = '/api/rbac') {
  const [rules, setRules] = useState<AccessRule[]>([]);
  const [loading, setLoading] = useState(false);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);

  // Determine if this is a feature-instance API path
  const isInstanceApi = apiBasePath.includes('/instance-roles/');

  /**
   * Fetch all rules for the role
   */
  const fetchRules = useCallback(async (): Promise<AccessRule[]> => {
    setLoading(true);
    setError(null);
    
    try {
      // Different endpoint structure for instance roles vs system roles
      const endpoint = isInstanceApi 
        ? `${apiBasePath}/rules`
        : `${apiBasePath}/rules/by-role/${roleId}`;
      
      const response = await api.get(endpoint);
      const fetchedRules = response.data?.items || response.data || [];
      setRules(fetchedRules);
      return fetchedRules;
    } catch (err: any) {
      const errorMsg = err.response?.data?.detail || err.message || 'Fehler beim Laden der Regeln';
      setError(errorMsg);
      console.error('Error fetching rules:', err);
      return [];
    } finally {
      setLoading(false);
    }
  }, [roleId, apiBasePath, isInstanceApi]);

  /**
   * Save all rules for the role
   */
  const saveRules = useCallback(async (rulesToSave: AccessRule[]): Promise<SaveResult> => {
    setSaving(true);
    setError(null);
    
    try {
      // Different endpoint structure for instance roles vs system roles
      const rulesEndpoint = isInstanceApi 
        ? `${apiBasePath}/rules`
        : `${apiBasePath}/rules/by-role/${roleId}`;
      
      // Get current rules from server
      const currentResponse = await api.get(rulesEndpoint);
      const currentRules: AccessRule[] = currentResponse.data?.items || currentResponse.data || [];
      const currentRuleIds = new Set(currentRules.map(r => r.id));
      
      // Determine changes
      const newRules = rulesToSave.filter(r => r.id.startsWith('temp-'));
      const existingRules = rulesToSave.filter(r => !r.id.startsWith('temp-'));
      const deletedRuleIds = [...currentRuleIds].filter(
        id => !existingRules.some(r => r.id === id)
      );
      
      // Delete removed rules
      for (const deletedId of deletedRuleIds) {
        const deleteEndpoint = isInstanceApi
          ? `${apiBasePath}/rules/${deletedId}`
          : `${apiBasePath}/rules/${deletedId}`;
        await api.delete(deleteEndpoint);
      }
      
      // Create new rules
      for (const rule of newRules) {
        const createEndpoint = isInstanceApi
          ? `${apiBasePath}/rules`
          : `${apiBasePath}/rules`;
        await api.post(createEndpoint, {
          roleId,
          context: rule.context,
          item: rule.item,
          view: rule.view,
          read: rule.read,
          create: rule.create,
          update: rule.update,
          delete: rule.delete,
        });
      }
      
      // Update existing rules
      for (const rule of existingRules) {
        const original = currentRules.find(r => r.id === rule.id);
        if (original && JSON.stringify(original) !== JSON.stringify(rule)) {
          const updateEndpoint = isInstanceApi
            ? `${apiBasePath}/rules/${rule.id}`
            : `${apiBasePath}/rules/${rule.id}`;
          await api.put(updateEndpoint, {
            view: rule.view,
            read: rule.read,
            create: rule.create,
            update: rule.update,
            delete: rule.delete,
          });
        }
      }
      
      // Refresh rules
      await fetchRules();
      
      return { success: true };
    } catch (err: any) {
      const errorMsg = err.response?.data?.detail || err.message || 'Fehler beim Speichern';
      setError(errorMsg);
      console.error('Error saving rules:', err);
      return { success: false, error: errorMsg };
    } finally {
      setSaving(false);
    }
  }, [roleId, apiBasePath, isInstanceApi, fetchRules]);

  /**
   * Get rules grouped by context
   */
  const getGroupedRules = useCallback((): GroupedRules => {
    return {
      DATA: rules.filter(r => r.context === 'DATA'),
      UI: rules.filter(r => r.context === 'UI'),
      RESOURCE: rules.filter(r => r.context === 'RESOURCE'),
    };
  }, [rules]);

  /**
   * Update a rule locally (not saved until saveRules is called)
   */
  const updateRuleLocally = useCallback((ruleId: string, updates: Partial<AccessRule>) => {
    setRules(prev => prev.map(r => 
      r.id === ruleId ? { ...r, ...updates } : r
    ));
  }, []);

  /**
   * Add a rule locally (not saved until saveRules is called)
   */
  const addRuleLocally = useCallback((rule: AccessRule) => {
    setRules(prev => [...prev, rule]);
  }, []);

  /**
   * Remove a rule locally (not saved until saveRules is called)
   */
  const removeRuleLocally = useCallback((ruleId: string) => {
    setRules(prev => prev.filter(r => r.id !== ruleId));
  }, []);

  return {
    rules,
    loading,
    saving,
    error,
    fetchRules,
    saveRules,
    getGroupedRules,
    updateRuleLocally,
    addRuleLocally,
    removeRuleLocally,
  };
}

export default useAccessRules;
