// ABOUTME: This file provides the security BLoC for managing authentication and security operations
// ABOUTME: Includes state management for authentication, key generation, and security configuration

import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../models/security/auth_method.dart';
import '../../models/security/security_settings.dart';
import '../../services/auth_service.dart';
import '../../services/key_management_service.dart';
import '../../services/secure_storage_service.dart';
import '../../utils/security_utils.dart';
import 'security_event.dart';
import 'security_state.dart';

/// BLoC for managing security operations and authentication state
class SecurityBloc extends Bloc<SecurityEvent, SecurityState> {
  final AuthService _authService;
  final KeyManagementService _keyManagement;
  final SecureStorageService _secureStorage;
  
  Timer? _sessionTimer;
  StreamSubscription? _sessionSubscription;

  SecurityBloc({
    AuthService? authService,
    KeyManagementService? keyManagement,
    SecureStorageService? secureStorage,
  }) : _authService = authService ?? AuthService(prefs: null),
       _keyManagement = keyManagement ?? KeyManagementService(),
       _secureStorage = secureStorage ?? SecureStorageService(),
       super(const SecurityInitialState()) {
    
    // Register event handlers
    on<SecurityInitializeEvent>(_onInitialize);
    on<SecurityCheckStatusEvent>(_onCheckStatus);
    on<SecurityAuthenticateEvent>(_onAuthenticate);
    on<SecurityLogoutEvent>(_onLogout);
    on<SecuritySetupPasswordEvent>(_onSetupPassword);
    on<SecuritySetupBiometricEvent>(_onSetupBiometric);
    on<SecurityChangeAuthMethodEvent>(_onChangeAuthMethod);
    on<SecurityGenerateKeysEvent>(_onGenerateKeys);
    on<SecurityRotateKeysEvent>(_onRotateKeys);
    on<SecurityToggleEncryptionEvent>(_onToggleEncryption);
    on<SecurityUpdateSettingsEvent>(_onUpdateSettings);
    on<SecurityCheckBiometricEvent>(_onCheckBiometric);
    on<SecurityValidateKeysEvent>(_onValidateKeys);
    on<SecurityExtendSessionEvent>(_onExtendSession);
    on<SecurityChangePasswordEvent>(_onChangePassword);
    on<SecurityResetEvent>(_onReset);
    on<SecurityBackupEvent>(_onBackup);
    on<SecurityRestoreEvent>(_onRestore);
    on<SecurityUpdatePoliciesEvent>(_onUpdatePolicies);
    on<SecurityMaintenanceEvent>(_onMaintenance);
    on<SecurityAuthFailureEvent>(_onAuthFailure);
    on<SecuritySessionTimeoutEvent>(_onSessionTimeout);
    on<SecurityAuditLogEvent>(_onAuditLog);
  }

  /// Handles security system initialization
  Future<void> _onInitialize(
    SecurityInitializeEvent event,
    Emitter<SecurityState> emit,
  ) async {
    emit(const SecurityInitializingState());

    try {
      // Initialize services
      final authService = await AuthService.create();
      
      // Load current security settings
      final authConfig = await authService.getAuthConfig();
      final settings = SecuritySettings(
        authConfig: authConfig,
        encryptionSettings: EncryptionSettings.defaultSettings(),
        policies: SecurityPolicies.defaultPolicies(),
        isFirstTimeSetup: !authConfig.isEnabled,
      );

      // Check if keys exist
      final hasKeyPair = await _keyManagement.hasKeyPair();
      
      // Check biometric availability
      final biometricAvailability = await authService.checkBiometricAvailability();

      // Check authentication status
      final isSessionValid = await authService.isSessionValid();
      final status = isSessionValid
          ? SecurityStatus(
              isAuthenticated: true,
              isSessionValid: true,
              lastAuthenticationAt: DateTime.now(),
            )
          : SecurityStatus.unauthenticated();

      // Determine initial state
      if (settings.isFirstTimeSetup) {
        final availableBiometrics = await authService.getAvailableBiometrics();
        emit(SecuritySetupRequiredState(
          availableBiometrics: availableBiometrics,
          canUseBiometric: biometricAvailability == BiometricAvailability.available,
        ));
      } else if (!isSessionValid && authConfig.requiresAuth) {
        emit(SecurityUnauthenticatedState(
          settings: settings,
          requiredMethod: authConfig.method,
          isLocked: authConfig.isLocked,
          lockTimeRemaining: authConfig.lockTimeRemaining,
          failedAttempts: authConfig.failedAttempts,
        ));
      } else {
        emit(SecurityReadyState(
          settings: settings,
          status: status,
          hasKeyPair: hasKeyPair,
          biometricAvailability: biometricAvailability,
        ));

        if (isSessionValid) {
          _startSessionMonitoring();
        }
      }

      // Log initialization
      add(const SecurityAuditLogEvent(action: 'security_initialized'));

    } catch (e) {
      emit(SecurityErrorState(
        error: 'Failed to initialize security system: $e',
        canRetry: true,
      ));
    }
  }

  /// Handles checking current security status
  Future<void> _onCheckStatus(
    SecurityCheckStatusEvent event,
    Emitter<SecurityState> emit,
  ) async {
    try {
      final isSessionValid = await _authService.isSessionValid();
      final authConfig = await _authService.getAuthConfig();
      
      if (!isSessionValid && authConfig.requiresAuth) {
        emit(SecurityUnauthenticatedState(
          settings: SecuritySettings.defaultSettings(),
          requiredMethod: authConfig.method,
          isLocked: authConfig.isLocked,
          lockTimeRemaining: authConfig.lockTimeRemaining,
          failedAttempts: authConfig.failedAttempts,
        ));
      }
    } catch (e) {
      emit(SecurityErrorState(error: 'Failed to check security status: $e'));
    }
  }

  /// Handles user authentication
  Future<void> _onAuthenticate(
    SecurityAuthenticateEvent event,
    Emitter<SecurityState> emit,
  ) async {
    try {
      final authConfig = await _authService.getAuthConfig();
      
      emit(SecurityAuthenticatingState(method: authConfig.method));

      // Perform authentication
      final result = await _authService.authenticate(password: event.password);

      if (result.success) {
        // Start session
        await _authService.startSession(result);
        
        // Get session info
        final sessionInfo = await _authService.getCurrentSession();
        
        // Update state
        final settings = SecuritySettings(
          authConfig: authConfig,
          encryptionSettings: EncryptionSettings.defaultSettings(),
          policies: SecurityPolicies.defaultPolicies(),
        );

        final status = SecurityStatus(
          isAuthenticated: true,
          isSessionValid: true,
          lastAuthenticationAt: result.timestamp,
        );

        emit(SecurityAuthenticatedState(
          settings: settings,
          status: status,
          sessionInfo: sessionInfo,
          authenticatedAt: result.timestamp,
        ));

        _startSessionMonitoring();

        // Log successful authentication
        add(SecurityAuditLogEvent(
          action: 'authentication_success',
          metadata: {'method': result.methodUsed.name},
        ));

      } else {
        // Handle authentication failure
        add(SecurityAuthFailureEvent(
          error: result.errorMessage ?? 'Authentication failed',
          method: result.methodUsed,
        ));
      }
    } catch (e) {
      emit(SecurityErrorState(error: 'Authentication error: $e'));
    }
  }

  /// Handles logout
  Future<void> _onLogout(
    SecurityLogoutEvent event,
    Emitter<SecurityState> emit,
  ) async {
    try {
      // End session
      await _authService.endSession();
      
      // Stop session monitoring
      _stopSessionMonitoring();
      
      // Get current config
      final authConfig = await _authService.getAuthConfig();
      
      // Update to unauthenticated state
      final settings = SecuritySettings(
        authConfig: authConfig,
        encryptionSettings: EncryptionSettings.defaultSettings(),
        policies: SecurityPolicies.defaultPolicies(),
      );

      if (authConfig.requiresAuth) {
        emit(SecurityUnauthenticatedState(
          settings: settings,
          requiredMethod: authConfig.method,
          isLocked: false,
          failedAttempts: 0,
        ));
      } else {
        emit(SecurityReadyState(
          settings: settings,
          status: SecurityStatus.unauthenticated(),
          hasKeyPair: await _keyManagement.hasKeyPair(),
          biometricAvailability: await _authService.checkBiometricAvailability(),
        ));
      }

      // Log logout
      add(const SecurityAuditLogEvent(action: 'logout'));

    } catch (e) {
      emit(SecurityErrorState(error: 'Logout error: $e'));
    }
  }

  /// Handles password authentication setup
  Future<void> _onSetupPassword(
    SecuritySetupPasswordEvent event,
    Emitter<SecurityState> emit,
  ) async {
    emit(const SecuritySetupState(
      setupMethod: AuthMethod.password,
      isInProgress: true,
    ));

    try {
      // Validate passwords match
      if (event.password != event.confirmPassword) {
        emit(const SecuritySetupState(
          setupMethod: AuthMethod.password,
          isInProgress: false,
          errorMessage: 'Passwords do not match',
        ));
        return;
      }

      // Setup password authentication
      await _authService.setupPasswordAuth(event.password);

      // Generate keys if needed
      if (!await _keyManagement.hasKeyPair()) {
        await _keyManagement.generateKeyPair();
      }

      // Update settings
      final authConfig = await _authService.getAuthConfig();
      final settings = SecuritySettings(
        authConfig: authConfig,
        encryptionSettings: EncryptionSettings.defaultSettings(),
        policies: SecurityPolicies.defaultPolicies(),
        isFirstTimeSetup: false,
      );

      emit(SecurityReadyState(
        settings: settings,
        status: SecurityStatus.unauthenticated(),
        hasKeyPair: true,
        biometricAvailability: await _authService.checkBiometricAvailability(),
      ));

      // Log setup completion
      add(const SecurityAuditLogEvent(action: 'password_setup_complete'));

    } catch (e) {
      emit(SecuritySetupState(
        setupMethod: AuthMethod.password,
        isInProgress: false,
        errorMessage: e.toString(),
      ));
    }
  }

  /// Handles biometric authentication setup
  Future<void> _onSetupBiometric(
    SecuritySetupBiometricEvent event,
    Emitter<SecurityState> emit,
  ) async {
    emit(const SecuritySetupState(
      setupMethod: AuthMethod.biometric,
      isInProgress: true,
    ));

    try {
      // Setup biometric authentication
      await _authService.setupBiometricAuth(
        withPassword: event.withPasswordFallback,
      );

      // Generate keys if needed
      if (!await _keyManagement.hasKeyPair()) {
        await _keyManagement.generateKeyPair();
      }

      // Update settings
      final authConfig = await _authService.getAuthConfig();
      final settings = SecuritySettings(
        authConfig: authConfig,
        encryptionSettings: EncryptionSettings.defaultSettings(),
        policies: SecurityPolicies.defaultPolicies(),
        isFirstTimeSetup: false,
      );

      emit(SecurityReadyState(
        settings: settings,
        status: SecurityStatus.unauthenticated(),
        hasKeyPair: true,
        biometricAvailability: BiometricAvailability.available,
      ));

      // Log setup completion
      add(const SecurityAuditLogEvent(action: 'biometric_setup_complete'));

    } catch (e) {
      emit(SecuritySetupState(
        setupMethod: AuthMethod.biometric,
        isInProgress: false,
        errorMessage: e.toString(),
      ));
    }
  }

  // Additional event handlers would continue here...
  // Due to space constraints, I'm including the key handlers

  /// Handles authentication failures
  Future<void> _onAuthFailure(
    SecurityAuthFailureEvent event,
    Emitter<SecurityState> emit,
  ) async {
    try {
      final authConfig = await _authService.getAuthConfig();
      final settings = SecuritySettings(
        authConfig: authConfig,
        encryptionSettings: EncryptionSettings.defaultSettings(),
        policies: SecurityPolicies.defaultPolicies(),
      );

      emit(SecurityUnauthenticatedState(
        settings: settings,
        requiredMethod: authConfig.method,
        isLocked: authConfig.isLocked,
        lockTimeRemaining: authConfig.lockTimeRemaining,
        failedAttempts: authConfig.failedAttempts,
      ));

      // Log authentication failure
      add(SecurityAuditLogEvent(
        action: 'authentication_failure',
        metadata: {
          'method': event.method.name,
          'error': event.error,
          'failed_attempts': authConfig.failedAttempts,
        },
      ));

    } catch (e) {
      emit(SecurityErrorState(error: 'Failed to handle auth failure: $e'));
    }
  }

  /// Placeholder implementations for remaining events
  Future<void> _onChangeAuthMethod(SecurityChangeAuthMethodEvent event, Emitter<SecurityState> emit) async {
    emit(const SecurityLoadingState(operation: 'Changing authentication method'));
    // Implementation would go here
  }

  Future<void> _onGenerateKeys(SecurityGenerateKeysEvent event, Emitter<SecurityState> emit) async {
    emit(const SecurityKeyOperationState(operation: 'Generating keys', isInProgress: true));
    // Implementation would go here
  }

  Future<void> _onRotateKeys(SecurityRotateKeysEvent event, Emitter<SecurityState> emit) async {
    emit(const SecurityKeyOperationState(operation: 'Rotating keys', isInProgress: true));
    // Implementation would go here
  }

  Future<void> _onToggleEncryption(SecurityToggleEncryptionEvent event, Emitter<SecurityState> emit) async {
    emit(const SecurityUpdatingState(updateType: 'encryption'));
    // Implementation would go here
  }

  Future<void> _onUpdateSettings(SecurityUpdateSettingsEvent event, Emitter<SecurityState> emit) async {
    emit(const SecurityUpdatingState(updateType: 'settings'));
    // Implementation would go here
  }

  Future<void> _onCheckBiometric(SecurityCheckBiometricEvent event, Emitter<SecurityState> emit) async {
    // Implementation would go here
  }

  Future<void> _onValidateKeys(SecurityValidateKeysEvent event, Emitter<SecurityState> emit) async {
    emit(const SecurityValidatingState(validationType: 'keys', isValid: true, errors: []));
    // Implementation would go here
  }

  Future<void> _onExtendSession(SecurityExtendSessionEvent event, Emitter<SecurityState> emit) async {
    // Implementation would go here
  }

  Future<void> _onChangePassword(SecurityChangePasswordEvent event, Emitter<SecurityState> emit) async {
    emit(const SecurityLoadingState(operation: 'Changing password'));
    // Implementation would go here
  }

  Future<void> _onReset(SecurityResetEvent event, Emitter<SecurityState> emit) async {
    emit(const SecurityLoadingState(operation: 'Resetting security'));
    // Implementation would go here
  }

  Future<void> _onBackup(SecurityBackupEvent event, Emitter<SecurityState> emit) async {
    emit(const SecurityBackupState(operation: 'backup', isInProgress: true));
    // Implementation would go here
  }

  Future<void> _onRestore(SecurityRestoreEvent event, Emitter<SecurityState> emit) async {
    emit(const SecurityBackupState(operation: 'restore', isInProgress: true));
    // Implementation would go here
  }

  Future<void> _onUpdatePolicies(SecurityUpdatePoliciesEvent event, Emitter<SecurityState> emit) async {
    emit(const SecurityUpdatingState(updateType: 'policies'));
    // Implementation would go here
  }

  Future<void> _onMaintenance(SecurityMaintenanceEvent event, Emitter<SecurityState> emit) async {
    emit(SecurityMaintenanceState(tasks: event.tasks));
    // Implementation would go here
  }

  Future<void> _onSessionTimeout(SecuritySessionTimeoutEvent event, Emitter<SecurityState> emit) async {
    add(const SecurityLogoutEvent());
  }

  Future<void> _onAuditLog(SecurityAuditLogEvent event, Emitter<SecurityState> emit) async {
    // Log security events (implementation would store in secure logging system)
    print('Security Audit: ${event.action} - ${event.metadata}');
  }

  /// Starts monitoring session timeout
  void _startSessionMonitoring() {
    _stopSessionMonitoring();
    
    _sessionTimer = Timer.periodic(const Duration(seconds: 30), (timer) async {
      try {
        final isValid = await _authService.isSessionValid();
        if (!isValid) {
          add(const SecuritySessionTimeoutEvent());
        } else {
          final session = await _authService.getCurrentSession();
          if (session != null) {
            final timeRemaining = session.timeRemaining;
            if (timeRemaining.inMinutes <= 5 && timeRemaining.inMinutes > 0) {
              // Emit session warning
              final authConfig = await _authService.getAuthConfig();
              final settings = SecuritySettings(
                authConfig: authConfig,
                encryptionSettings: EncryptionSettings.defaultSettings(),
                policies: SecurityPolicies.defaultPolicies(),
              );
              final status = SecurityStatus(
                isAuthenticated: true,
                isSessionValid: true,
                sessionExpiresAt: session.expiresAt,
              );
              emit(SecuritySessionWarningState(
                timeRemaining: timeRemaining,
                settings: settings,
                status: status,
              ));
            }
          }
        }
      } catch (e) {
        // Handle session monitoring error
        add(const SecuritySessionTimeoutEvent());
      }
    });
  }

  /// Stops session monitoring
  void _stopSessionMonitoring() {
    _sessionTimer?.cancel();
    _sessionTimer = null;
    _sessionSubscription?.cancel();
    _sessionSubscription = null;
  }

  @override
  Future<void> close() {
    _stopSessionMonitoring();
    return super.close();
  }
}
