import 'dart:async';

import 'package:logging/logging.dart';

/// Mutex to prevent concurrent token refresh operations
/// This ensures only one refresh operation happens at a time,
/// preventing race conditions during app startup when multiple
/// providers try to refresh tokens simultaneously.
class TokenRefreshMutex {
  static final _instance = TokenRefreshMutex._();
  factory TokenRefreshMutex() => _instance;
  TokenRefreshMutex._();

  static final _logger = Logger('service.authorization.token_mutex');
  
  Completer<String>? _currentRefresh;
  Completer<void>? _currentRotation;
  
  /// Execute a token refresh operation with mutex protection
  /// If another refresh is in progress, wait for it to complete
  Future<String> executeRefresh(Future<String> Function() refreshOperation) async {
    if (_currentRefresh != null) {
      _logger.fine('Token refresh already in progress, waiting for completion');
      return await _currentRefresh!.future;
    }
    
    _logger.fine('Starting new token refresh operation');
    _currentRefresh = Completer<String>();
    
    try {
      final result = await refreshOperation();
      if (_currentRefresh != null) {
        _currentRefresh!.complete(result);
        _logger.fine('Token refresh completed successfully');
      }
      return result;
    } catch (e, st) {
      _logger.warning('Token refresh failed', e, st);
      if (_currentRefresh != null) {
        _currentRefresh!.completeError(e, st);
      }
      rethrow;
    } finally {
      _currentRefresh = null;
    }
  }
  
  /// Execute a token rotation operation with mutex protection
  /// If another rotation is in progress, wait for it to complete
  Future<void> executeRotation(Future<void> Function() rotationOperation) async {
    if (_currentRotation != null) {
      _logger.fine('Token rotation already in progress, waiting for completion');
      return await _currentRotation!.future;
    }
    
    _logger.fine('Starting new token rotation operation');
    _currentRotation = Completer<void>();
    
    try {
      await rotationOperation();
      if (_currentRotation != null) {
        _currentRotation!.complete();
        _logger.fine('Token rotation completed successfully');
      }
    } catch (e, st) {
      _logger.warning('Token rotation failed', e, st);
      if (_currentRotation != null) {
        _currentRotation!.completeError(e, st);
      }
      rethrow;
    } finally {
      _currentRotation = null;
    }
  }
  
  /// Check if a refresh operation is currently in progress
  bool get isRefreshInProgress => _currentRefresh != null;
  
  /// Check if a rotation operation is currently in progress
  bool get isRotationInProgress => _currentRotation != null;
  
  /// Get current status for debugging
  Map<String, dynamic> getStatus() {
    return {
      'refreshInProgress': isRefreshInProgress,
      'rotationInProgress': isRotationInProgress,
      'timestamp': DateTime.now().toIso8601String(),
    };
  }
  
  /// Force reset the mutex (for testing or emergency situations)
  void forceReset() {
    _logger.warning('Force resetting token refresh mutex');
    if (_currentRefresh != null && !_currentRefresh!.isCompleted) {
      _currentRefresh!.completeError(Exception('Mutex force reset'));
    }
    if (_currentRotation != null && !_currentRotation!.isCompleted) {
      _currentRotation!.completeError(Exception('Mutex force reset'));
    }
    _currentRefresh = null;
    _currentRotation = null;
  }
} 