import 'dart:async';

import 'package:flutter_bloc/flutter_bloc.dart';

import '../../../data/services/coordination_service.dart';
import '../../../domain/entities/camera_lock.dart';
import 'lock_event.dart';
import 'lock_state.dart';

class LockBloc extends Bloc<LockEvent, LockState> {
  final CoordinationService _coordinationService;

  StreamSubscription? _locksSub;
  StreamSubscription? _notifSub;
  StreamSubscription? _connSub;

  LockBloc({
    required CoordinationService coordinationService,
    required String keyboardId,
  })  : _coordinationService = coordinationService,
        super(const LockState()) {
    on<TryLock>(_onTryLock);
    on<ReleaseLock>(_onReleaseLock);
    on<ReleaseAllLocks>(_onReleaseAllLocks);
    on<RequestTakeover>(_onRequestTakeover);
    on<ConfirmTakeover>(_onConfirmTakeover);
    on<ResetLockExpiration>(_onResetLockExpiration);
    on<LocksUpdated>(_onLocksUpdated);
    on<LockNotificationReceived>(_onLockNotificationReceived);
    on<CoordinatorConnectionChanged>(_onCoordinatorConnectionChanged);

    // Subscribe to coordinator streams
    _locksSub = _coordinationService.locks.listen((locks) {
      add(LocksUpdated(locks));
    });

    _notifSub = _coordinationService.notifications.listen((notification) {
      if (notification != null) {
        add(LockNotificationReceived(notification));
      }
    });

    _connSub = _coordinationService.connected.listen((connected) {
      add(CoordinatorConnectionChanged(connected));
    });
  }

  Future<void> _onTryLock(TryLock event, Emitter<LockState> emit) async {
    final result = await _coordinationService.tryLock(
      event.cameraId,
      priority: event.priority,
    );

    if (!result.acquired) {
      final lock = result.lock;
      final owner = lock?.ownerName ?? 'unknown';
      emit(state.copyWith(
        lastNotification: 'Camera ${event.cameraId} locked by $owner',
      ));
    }
  }

  Future<void> _onReleaseLock(
      ReleaseLock event, Emitter<LockState> emit) async {
    await _coordinationService.releaseLock(event.cameraId);
  }

  Future<void> _onReleaseAllLocks(
      ReleaseAllLocks event, Emitter<LockState> emit) async {
    final myLocks = await _coordinationService.getMyLockedCameras();
    for (final cameraId in myLocks) {
      await _coordinationService.releaseLock(cameraId);
    }
  }

  Future<void> _onRequestTakeover(
      RequestTakeover event, Emitter<LockState> emit) async {
    final success = await _coordinationService.requestTakeover(
      event.cameraId,
      priority: event.priority,
    );

    if (success) {
      emit(state.copyWith(
        lastNotification: 'Takeover requested for camera ${event.cameraId}',
      ));
    }
  }

  Future<void> _onConfirmTakeover(
      ConfirmTakeover event, Emitter<LockState> emit) async {
    await _coordinationService.confirmTakeover(
        event.cameraId, event.confirm);
    emit(state.copyWith(clearPendingTakeover: true));
  }

  Future<void> _onResetLockExpiration(
      ResetLockExpiration event, Emitter<LockState> emit) async {
    await _coordinationService.resetExpiration(event.cameraId);
  }

  void _onLocksUpdated(LocksUpdated event, Emitter<LockState> emit) {
    emit(state.copyWith(locks: event.locks));
  }

  void _onLockNotificationReceived(
      LockNotificationReceived event, Emitter<LockState> emit) {
    final notification = event.notification;

    switch (notification.type) {
      case CameraLockNotificationType.confirmTakeOver:
        // Show takeover confirmation dialog
        emit(state.copyWith(
          pendingTakeover: TakeoverRequest(
            cameraId: notification.cameraId,
            requestingKeyboard: notification.copilotName,
          ),
        ));
        break;

      case CameraLockNotificationType.takenOver:
        emit(state.copyWith(
          lastNotification:
              'Camera ${notification.cameraId} taken over by ${notification.copilotName}',
        ));
        break;

      case CameraLockNotificationType.expireSoon:
        emit(state.copyWith(
          lastNotification:
              'Lock on camera ${notification.cameraId} expiring soon',
        ));
        break;

      case CameraLockNotificationType.confirmed:
        emit(state.copyWith(
          lastNotification:
              'Takeover confirmed for camera ${notification.cameraId}',
        ));
        break;

      case CameraLockNotificationType.rejected:
        emit(state.copyWith(
          lastNotification:
              'Takeover rejected for camera ${notification.cameraId}',
        ));
        break;

      case CameraLockNotificationType.unlocked:
      case CameraLockNotificationType.acquired:
        // Handled by lock state updates
        break;
    }
  }

  void _onCoordinatorConnectionChanged(
      CoordinatorConnectionChanged event, Emitter<LockState> emit) {
    emit(state.copyWith(coordinatorConnected: event.connected));
  }

  @override
  Future<void> close() {
    _locksSub?.cancel();
    _notifSub?.cancel();
    _connSub?.cancel();
    return super.close();
  }
}
