/**
 * Biometrics Service
 *
 * Handles biometric authentication (Face ID, Touch ID, Fingerprint)
 */

import * as LocalAuthentication from 'expo-local-authentication';
import * as SecureStore from 'expo-secure-store';
import { Platform } from 'react-native';
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import AsyncStorage from '@react-native-async-storage/async-storage';

// Types
export type BiometricType = 'fingerprint' | 'facial' | 'iris' | 'none';

export interface BiometricCapabilities {
  isAvailable: boolean;
  isEnrolled: boolean;
  types: BiometricType[];
  primaryType: BiometricType;
  securityLevel: LocalAuthentication.SecurityLevel;
}

export interface BiometricSettings {
  enabled: boolean;
  enabledAt: number | null;
  lastUsedAt: number | null;
}

// Storage keys
const BIOMETRIC_ENABLED_KEY = 'biometric_enabled';
const BIOMETRIC_TOKEN_KEY = 'biometric_auth_token';

// State
interface BiometricState {
  settings: BiometricSettings;
  capabilities: BiometricCapabilities | null;
}

interface BiometricActions {
  setSettings: (settings: Partial<BiometricSettings>) => void;
  setCapabilities: (capabilities: BiometricCapabilities) => void;
  enable: () => void;
  disable: () => void;
  updateLastUsed: () => void;
}

// Biometrics Store
export const useBiometricStore = create<BiometricState & BiometricActions>()(
  persist(
    (set) => ({
      // State
      settings: {
        enabled: false,
        enabledAt: null,
        lastUsedAt: null,
      },
      capabilities: null,

      // Actions
      setSettings: (newSettings) =>
        set((state) => ({
          settings: { ...state.settings, ...newSettings },
        })),

      setCapabilities: (capabilities) => set({ capabilities }),

      enable: () =>
        set((state) => ({
          settings: {
            ...state.settings,
            enabled: true,
            enabledAt: Date.now(),
          },
        })),

      disable: () =>
        set((state) => ({
          settings: {
            ...state.settings,
            enabled: false,
            enabledAt: null,
            lastUsedAt: null,
          },
        })),

      updateLastUsed: () =>
        set((state) => ({
          settings: {
            ...state.settings,
            lastUsedAt: Date.now(),
          },
        })),
    }),
    {
      name: 'biometric-storage',
      storage: createJSONStorage(() => AsyncStorage),
      partialize: (state) => ({
        settings: state.settings,
      }),
    }
  )
);

// Convert LocalAuthentication types to our types
const convertBiometricType = (
  type: LocalAuthentication.AuthenticationType
): BiometricType => {
  switch (type) {
    case LocalAuthentication.AuthenticationType.FINGERPRINT:
      return 'fingerprint';
    case LocalAuthentication.AuthenticationType.FACIAL_RECOGNITION:
      return 'facial';
    case LocalAuthentication.AuthenticationType.IRIS:
      return 'iris';
    default:
      return 'none';
  }
};

// Get user-friendly name for biometric type
export const getBiometricTypeName = (type: BiometricType): string => {
  switch (type) {
    case 'fingerprint':
      return Platform.OS === 'ios' ? 'Touch ID' : 'Huella Digital';
    case 'facial':
      return Platform.OS === 'ios' ? 'Face ID' : 'Reconocimiento Facial';
    case 'iris':
      return 'Escaneo de Iris';
    default:
      return 'Biométrico';
  }
};

// Biometric service
export const biometricService = {
  // Check device capabilities
  checkCapabilities: async (): Promise<BiometricCapabilities> => {
    try {
      const hasHardware = await LocalAuthentication.hasHardwareAsync();
      const isEnrolled = await LocalAuthentication.isEnrolledAsync();
      const supportedTypes = await LocalAuthentication.supportedAuthenticationTypesAsync();
      const securityLevel = await LocalAuthentication.getEnrolledLevelAsync();

      const types = supportedTypes.map(convertBiometricType);
      const primaryType = types.length > 0 ? types[0] : 'none';

      const capabilities: BiometricCapabilities = {
        isAvailable: hasHardware,
        isEnrolled: isEnrolled,
        types,
        primaryType,
        securityLevel,
      };

      useBiometricStore.getState().setCapabilities(capabilities);
      return capabilities;
    } catch (error) {
      console.error('Error checking biometric capabilities:', error);
      return {
        isAvailable: false,
        isEnrolled: false,
        types: [],
        primaryType: 'none',
        securityLevel: LocalAuthentication.SecurityLevel.NONE,
      };
    }
  },

  // Authenticate with biometrics
  authenticate: async (options?: {
    promptMessage?: string;
    cancelLabel?: string;
    fallbackLabel?: string;
    disableDeviceFallback?: boolean;
  }): Promise<{
    success: boolean;
    error?: string;
    warning?: string;
  }> => {
    try {
      const capabilities = await biometricService.checkCapabilities();

      if (!capabilities.isAvailable) {
        return {
          success: false,
          error: 'El dispositivo no soporta autenticación biométrica',
        };
      }

      if (!capabilities.isEnrolled) {
        return {
          success: false,
          error: 'No hay datos biométricos registrados en el dispositivo',
        };
      }

      const result = await LocalAuthentication.authenticateAsync({
        promptMessage: options?.promptMessage || 'Autenticar con biometría',
        cancelLabel: options?.cancelLabel || 'Cancelar',
        fallbackLabel: options?.fallbackLabel || 'Usar contraseña',
        disableDeviceFallback: options?.disableDeviceFallback ?? false,
      });

      if (result.success) {
        useBiometricStore.getState().updateLastUsed();
        return { success: true };
      }

      // Handle specific errors
      switch (result.error) {
        case 'user_cancel':
          return { success: false, error: 'Autenticación cancelada' };
        case 'user_fallback':
          return { success: false, error: 'Usar método alternativo' };
        case 'system_cancel':
          return { success: false, error: 'Autenticación cancelada por el sistema' };
        case 'lockout':
          return {
            success: false,
            error: 'Demasiados intentos fallidos. Intenta más tarde.',
          };
        case 'lockout_permanent':
          return {
            success: false,
            error: 'Biometría bloqueada. Usa tu código de acceso.',
          };
        case 'not_enrolled':
          return {
            success: false,
            error: 'No hay datos biométricos registrados',
          };
        default:
          return {
            success: false,
            error: 'Error de autenticación',
            warning: result.warning,
          };
      }
    } catch (error) {
      console.error('Biometric authentication error:', error);
      return {
        success: false,
        error: 'Error inesperado durante la autenticación',
      };
    }
  },

  // Enable biometric login
  enableBiometricLogin: async (authToken: string): Promise<boolean> => {
    try {
      // Store token securely
      await SecureStore.setItemAsync(BIOMETRIC_TOKEN_KEY, authToken, {
        keychainAccessible: SecureStore.WHEN_PASSCODE_SET_THIS_DEVICE_ONLY,
      });

      useBiometricStore.getState().enable();
      return true;
    } catch (error) {
      console.error('Error enabling biometric login:', error);
      return false;
    }
  },

  // Disable biometric login
  disableBiometricLogin: async (): Promise<boolean> => {
    try {
      await SecureStore.deleteItemAsync(BIOMETRIC_TOKEN_KEY);
      useBiometricStore.getState().disable();
      return true;
    } catch (error) {
      console.error('Error disabling biometric login:', error);
      return false;
    }
  },

  // Login with biometrics
  loginWithBiometrics: async (options?: {
    promptMessage?: string;
  }): Promise<{
    success: boolean;
    token?: string;
    error?: string;
  }> => {
    // First authenticate
    const authResult = await biometricService.authenticate({
      promptMessage: options?.promptMessage || 'Inicia sesión con biometría',
      disableDeviceFallback: false,
    });

    if (!authResult.success) {
      return { success: false, error: authResult.error };
    }

    // Get stored token
    try {
      const token = await SecureStore.getItemAsync(BIOMETRIC_TOKEN_KEY);

      if (!token) {
        return {
          success: false,
          error: 'No hay sesión biométrica configurada',
        };
      }

      return { success: true, token };
    } catch (error) {
      console.error('Error getting biometric token:', error);
      return {
        success: false,
        error: 'Error al obtener las credenciales',
      };
    }
  },

  // Check if biometric login is available
  isBiometricLoginAvailable: async (): Promise<boolean> => {
    const capabilities = await biometricService.checkCapabilities();
    const { settings } = useBiometricStore.getState();

    return capabilities.isAvailable && capabilities.isEnrolled && settings.enabled;
  },

  // Check if there's a stored biometric token
  hasBiometricCredentials: async (): Promise<boolean> => {
    try {
      const token = await SecureStore.getItemAsync(BIOMETRIC_TOKEN_KEY);
      return token !== null;
    } catch {
      return false;
    }
  },
};
