import 'dart:async';

import 'package:flutter_bloc/flutter_bloc.dart';

import '../../../config/app_config.dart';
import '../../../data/services/bridge_service.dart';
import 'connection_event.dart';
import 'connection_state.dart';

class ConnectionBloc extends Bloc<ConnectionEvent, ConnectionState> {
  final BridgeService _bridgeService;
  final AppConfig _config;
  StreamSubscription? _statusSubscription;

  ConnectionBloc({
    required BridgeService bridgeService,
    required AppConfig config,
  })  : _bridgeService = bridgeService,
        _config = config,
        super(const ConnectionState()) {
    on<ConnectAll>(_onConnectAll);
    on<ConnectServer>(_onConnectServer);
    on<DisconnectServer>(_onDisconnectServer);
    on<DisconnectAll>(_onDisconnectAll);
    on<RetryConnections>(_onRetryConnections);
    on<ConnectionStatusUpdated>(_onConnectionStatusUpdated);

    // Subscribe to connection status changes
    _statusSubscription = _bridgeService.connectionStatus.listen((status) {
      add(ConnectionStatusUpdated(status));
    });
  }

  Future<void> _onConnectAll(
    ConnectAll event,
    Emitter<ConnectionState> emit,
  ) async {
    emit(state.copyWith(overallStatus: ConnectionOverallStatus.connecting));

    try {
      await _bridgeService.connectAll();
    } catch (e) {
      emit(state.copyWith(
        overallStatus: ConnectionOverallStatus.disconnected,
        error: e.toString(),
      ));
    }
  }

  Future<void> _onConnectServer(
    ConnectServer event,
    Emitter<ConnectionState> emit,
  ) async {
    try {
      await _bridgeService.connect(event.serverId);
    } catch (e) {
      emit(state.copyWith(error: 'Failed to connect to ${event.serverId}: $e'));
    }
  }

  Future<void> _onDisconnectServer(
    DisconnectServer event,
    Emitter<ConnectionState> emit,
  ) async {
    await _bridgeService.disconnect(event.serverId);
  }

  Future<void> _onDisconnectAll(
    DisconnectAll event,
    Emitter<ConnectionState> emit,
  ) async {
    await _bridgeService.disconnectAll();
    emit(state.copyWith(overallStatus: ConnectionOverallStatus.disconnected));
  }

  Future<void> _onRetryConnections(
    RetryConnections event,
    Emitter<ConnectionState> emit,
  ) async {
    // Retry only disconnected servers
    final disconnected = state.serverStatus.entries
        .where((e) => !e.value)
        .map((e) => e.key)
        .toList();

    for (final serverId in disconnected) {
      await _bridgeService.connect(serverId);
    }
  }

  void _onConnectionStatusUpdated(
    ConnectionStatusUpdated event,
    Emitter<ConnectionState> emit,
  ) {
    final status = event.status;
    ConnectionOverallStatus overall;

    if (status.isEmpty) {
      overall = ConnectionOverallStatus.disconnected;
    } else if (status.values.every((v) => v)) {
      overall = ConnectionOverallStatus.connected;
    } else if (status.values.any((v) => v)) {
      overall = ConnectionOverallStatus.partial;
    } else {
      overall = ConnectionOverallStatus.disconnected;
    }

    emit(state.copyWith(
      overallStatus: overall,
      serverStatus: status,
      error: null,
    ));
  }

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