import 'dart:async';

import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_event.dart';
import 'package:syncrow_web/pages/device_managment/ac/bloc/ac_state.dart';
import 'package:syncrow_web/pages/device_managment/ac/model/ac_model.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
import 'package:syncrow_web/services/batch_control_devices_service.dart';
import 'package:syncrow_web/services/control_device_service.dart';
import 'package:syncrow_web/services/devices_mang_api.dart';

class AcBloc extends Bloc<AcsEvent, AcsState> {
  late AcStatusModel deviceStatus;
  final String deviceId;
  final ControlDeviceService controlDeviceService;
  final BatchControlDevicesService batchControlDevicesService;
  Timer? _countdownTimer;

  AcBloc({
    required this.deviceId,
    required this.controlDeviceService,
    required this.batchControlDevicesService,
  }) : super(AcsInitialState()) {
    on<AcFetchDeviceStatusEvent>(_onFetchAcStatus);
    on<AcFetchBatchStatusEvent>(_onFetchAcBatchStatus);
    on<AcControlEvent>(_onAcControl);
    on<AcBatchControlEvent>(_onAcBatchControl);
    on<AcFactoryResetEvent>(_onFactoryReset);
    on<AcStatusUpdated>(_onAcStatusUpdated);
    on<OnClose>(_onClose);
    on<IncreaseTimeEvent>(_handleIncreaseTime);
    on<DecreaseTimeEvent>(_handleDecreaseTime);
    on<UpdateTimerEvent>(_handleUpdateTimer);
    on<ToggleScheduleEvent>(_handleToggleTimer);
    on<ApiCountdownValueEvent>(_handleApiCountdownValue);
  }
  bool timerActive = false;
  int scheduledHours = 0;
  int scheduledMinutes = 0;

  FutureOr<void> _onFetchAcStatus(
    AcFetchDeviceStatusEvent event,
    Emitter<AcsState> emit,
  ) async {
    emit(AcsLoadingState());
    try {
      final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
      deviceStatus = AcStatusModel.fromJson(event.deviceId, status.status);
      if (deviceStatus.countdown1 != 0) {
        final totalMinutes = deviceStatus.countdown1 * 6;
        scheduledHours = totalMinutes ~/ 60;
        scheduledMinutes = totalMinutes % 60;
        timerActive = true;
        _startCountdownTimer(emit);
      }

      emit(ACStatusLoaded(
        status: deviceStatus,
        scheduledHours: scheduledHours,
        scheduledMinutes: scheduledMinutes,
        isTimerActive: timerActive,
      ));

      _listenToChanges(event.deviceId);
    } catch (e) {
      emit(AcsFailedState(error: e.toString()));
    }
  }

  StreamSubscription<DatabaseEvent>? _deviceStatusSubscription;

  void _listenToChanges(String deviceId) {
    try {
      final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
      _deviceStatusSubscription = ref.onValue.listen((DatabaseEvent event) async {
        if (event.snapshot.value == null) return;

        final usersMap = event.snapshot.value! as Map<dynamic, dynamic>;

        final statusList = <Status>[];

        usersMap['status'].forEach((element) {
          statusList.add(Status(code: element['code'], value: element['value']));
        });


        deviceStatus =
            AcStatusModel.fromJson(usersMap['productUuid'], statusList);

        deviceStatus = AcStatusModel.fromJson(usersMap['productUuid'], statusList);
        print('Device status updated: ${deviceStatus.acSwitch}');


        if (!isClosed) {
          add(AcStatusUpdated(deviceStatus));
        }
      });
    } catch (_) {}
  }

  void _onAcStatusUpdated(
    AcStatusUpdated event,
    Emitter<AcsState> emit,
  ) {
    deviceStatus = event.deviceStatus;
    emit(ACStatusLoaded(status: deviceStatus));
  }

  FutureOr<void> _onAcControl(
    AcControlEvent event,
    Emitter<AcsState> emit,
  ) async {
    try {
      _updateDeviceFunctionFromCode(event.code, event.value);
      emit(ACStatusLoaded(status: deviceStatus));
      await controlDeviceService.controlDevice(
        deviceUuid: event.deviceId,
        status: Status(code: event.code, value: event.value),
      );
    } catch (e) {}
  }

  FutureOr<void> _onFetchAcBatchStatus(
    AcFetchBatchStatusEvent event,
    Emitter<AcsState> emit,
  ) async {
    emit(AcsLoadingState());
    try {
      final status = await DevicesManagementApi().getBatchStatus(event.devicesIds);
      deviceStatus = AcStatusModel.fromJson(event.devicesIds.first, status.status);
      emit(ACStatusLoaded(status: deviceStatus));
    } catch (e) {
      emit(AcsFailedState(error: e.toString()));
    }
  }

  FutureOr<void> _onAcBatchControl(
    AcBatchControlEvent event,
    Emitter<AcsState> emit,
  ) async {
    _updateDeviceFunctionFromCode(event.code, event.value);
    emit(ACStatusLoaded(status: deviceStatus));

    try {
      await batchControlDevicesService.batchControlDevices(
        uuids: event.devicesIds,
        code: event.code,
        value: event.value,
      );
    } catch (e) {}
  }

  Future<void> _onFactoryReset(
    AcFactoryResetEvent event,
    Emitter<AcsState> emit,
  ) async {
    emit(AcsLoadingState());
    try {
      final response = await DevicesManagementApi().factoryReset(
        event.factoryResetModel,
        event.deviceId,
      );
      if (!response) {
        emit(const AcsFailedState(error: 'Failed'));
      } else {
        add(AcFetchDeviceStatusEvent(event.deviceId));
      }
    } catch (e) {
      emit(AcsFailedState(error: e.toString()));
    }
  }

  void _onClose(
    OnClose event,
    Emitter<AcsState> emit,
  ) {
    _countdownTimer?.cancel();
  }

  void _handleIncreaseTime(IncreaseTimeEvent event, Emitter<AcsState> emit) {
    if (state is! ACStatusLoaded) return;
    final currentState = state as ACStatusLoaded;
    var newHours = scheduledHours;
    var newMinutes = scheduledMinutes + 30;
    newHours += newMinutes ~/ 60;
    newMinutes = newMinutes % 60;
    if (newHours > 23) {
      newHours = 23;
      newMinutes = 59;
    }
    scheduledHours = newHours;
    scheduledMinutes = newMinutes;

    emit(currentState.copyWith(
      scheduledHours: scheduledHours,
      scheduledMinutes: scheduledMinutes,
    ));
  }

  void _handleDecreaseTime(
    DecreaseTimeEvent event,
    Emitter<AcsState> emit,
  ) {
    if (state is! ACStatusLoaded) return;
    final currentState = state as ACStatusLoaded;
    var totalMinutes = (scheduledHours * 60) + scheduledMinutes;
    totalMinutes = (totalMinutes - 30).clamp(0, 1440);
    scheduledHours = totalMinutes ~/ 60;
    scheduledMinutes = totalMinutes % 60;

    emit(currentState.copyWith(
      scheduledHours: scheduledHours,
      scheduledMinutes: scheduledMinutes,
    ));
  }

  Future<void> _handleToggleTimer(
    ToggleScheduleEvent event,
    Emitter<AcsState> emit,
  ) async {
    if (state is! ACStatusLoaded) return;
    final currentState = state as ACStatusLoaded;

    timerActive = !timerActive;

    if (timerActive) {
      final totalMinutes = scheduledHours * 60 + scheduledMinutes;
      if (totalMinutes <= 0) {
        timerActive = false;
        emit(currentState.copyWith(isTimerActive: timerActive));
        return;
      }

      try {
        final scaledValue = totalMinutes ~/ 6;
        final success = await controlDeviceService.controlDevice(
          deviceUuid: deviceId,
          status: Status(code: 'countdown_time', value: scaledValue),
        );

        if (success) {
          _startCountdownTimer(emit);
          emit(currentState.copyWith(isTimerActive: timerActive));
        } else {
          timerActive = false;
          emit(const AcsFailedState(error: 'Failed to set timer'));
        }
      } catch (e) {
        timerActive = false;
        emit(AcsFailedState(error: e.toString()));
      }
    } else {
      try {
        final success = await controlDeviceService.controlDevice(
          deviceUuid: deviceId,
          status: Status(code: 'countdown_time', value: 0),
        );

        if (success) {
          _countdownTimer?.cancel();
          scheduledHours = 0;
          scheduledMinutes = 0;
          emit(currentState.copyWith(
            isTimerActive: timerActive,
            scheduledHours: 0,
            scheduledMinutes: 0,
          ));
        } else {
          emit(const AcsFailedState(error: 'Failed to stop timer'));
        }
      } catch (e) {
        emit(AcsFailedState(error: e.toString()));
      }
    }
  }

  void _startCountdownTimer(Emitter<AcsState> emit) {
    _countdownTimer?.cancel();
    var totalSeconds = (scheduledHours * 3600) + (scheduledMinutes * 60);

    _countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
      if (totalSeconds > 0) {
        totalSeconds--;
        scheduledHours = totalSeconds ~/ 3600;
        scheduledMinutes = (totalSeconds % 3600) ~/ 60;
        if (!isClosed) {
          add(UpdateTimerEvent());
        }
      } else {
        _countdownTimer?.cancel();
        timerActive = false;
        scheduledHours = 0;
        scheduledMinutes = 0;
        if (!isClosed) {
          add(TimerCompletedEvent());
        }
      }
    });
  }

  void _handleUpdateTimer(
    UpdateTimerEvent event,
    Emitter<AcsState> emit,
  ) {
    if (state is ACStatusLoaded) {
      final currentState = state as ACStatusLoaded;
      emit(currentState.copyWith(
        scheduledHours: scheduledHours,
        scheduledMinutes: scheduledMinutes,
        isTimerActive: timerActive,
      ));
    }
  }

  void _handleApiCountdownValue(
      ApiCountdownValueEvent event, Emitter<AcsState> emit) {
    if (state is ACStatusLoaded) {
      final totalMinutes = event.apiValue * 6;
      scheduledMinutes = totalMinutes % 60;
      _startCountdownTimer(
        emit,
      );
      if (!isClosed) {
        add(UpdateTimerEvent());
      }
    }
  }

  void _updateDeviceFunctionFromCode(String code, dynamic value) {
    switch (code) {
      case 'switch':
        if (value is bool) {
          deviceStatus = deviceStatus.copyWith(acSwitch: value);
        }
        break;
      case 'temp_set':
        if (value is int) {
          deviceStatus = deviceStatus.copyWith(tempSet: value);
        }
        break;
      case 'mode':
        if (value is String) {
          deviceStatus = deviceStatus.copyWith(modeString: value);
        }
        break;
      case 'level':
        if (value is String) {
          deviceStatus = deviceStatus.copyWith(fanSpeedsString: value);
        }
        break;
      case 'child_lock':
        if (value is bool) {
          deviceStatus = deviceStatus.copyWith(childLock: value);
        }
        break;
      case 'countdown_time':
        if (value is int) {
          deviceStatus = deviceStatus.copyWith(countdown1: value);
        }
        break;
      default:
        break;
    }
  }

  @override
  Future<void> close() {
    add(OnClose());
    _countdownTimer?.cancel();
    _deviceStatusSubscription?.cancel();
    return super.close();
  }
}
