import 'package:flutter_bloc/flutter_bloc.dart';
import '../../domain/usecases/apply_quick_set_usecase.dart';
import '../../domain/usecases/get_weekly_availability_usecase.dart';
import '../../domain/usecases/update_day_availability_usecase.dart';
import 'availability_event.dart';
import 'availability_state.dart';

class AvailabilityBloc extends Bloc<AvailabilityEvent, AvailabilityState> {
  final GetWeeklyAvailabilityUseCase getWeeklyAvailability;
  final UpdateDayAvailabilityUseCase updateDayAvailability;
  final ApplyQuickSetUseCase applyQuickSet;

  AvailabilityBloc({
    required this.getWeeklyAvailability,
    required this.updateDayAvailability,
    required this.applyQuickSet,
  }) : super(AvailabilityInitial()) {
    on<LoadAvailability>(_onLoadAvailability);
    on<SelectDate>(_onSelectDate);
    on<NavigateWeek>(_onNavigateWeek);
    on<ToggleDayStatus>(_onToggleDayStatus);
    on<ToggleSlotStatus>(_onToggleSlotStatus);
    on<PerformQuickSet>(_onPerformQuickSet);
  }

  Future<void> _onLoadAvailability(
    LoadAvailability event,
    Emitter<AvailabilityState> emit,
  ) async {
    emit(AvailabilityLoading());
    try {
      final days = await getWeeklyAvailability(
          GetWeeklyAvailabilityParams(event.weekStart));
      emit(AvailabilityLoaded(
        days: days,
        currentWeekStart: event.weekStart,
        selectedDate: event.preselectedDate ??
            (days.isNotEmpty ? days.first.date : DateTime.now()),
      ));
    } catch (e) {
      emit(AvailabilityError(e.toString()));
    }
  }

  void _onSelectDate(SelectDate event, Emitter<AvailabilityState> emit) {
    if (state is AvailabilityLoaded) {
      // Clear success message on navigation
      emit((state as AvailabilityLoaded).copyWith(
        selectedDate: event.date,
        clearSuccessMessage: true,
      ));
    }
  }

  Future<void> _onNavigateWeek(
    NavigateWeek event,
    Emitter<AvailabilityState> emit,
  ) async {
    if (state is AvailabilityLoaded) {
      final currentState = state as AvailabilityLoaded;
      
      // Clear message
      emit(currentState.copyWith(clearSuccessMessage: true));

      final newWeekStart = currentState.currentWeekStart
          .add(Duration(days: event.direction * 7));
      
      final diff = currentState.selectedDate.difference(currentState.currentWeekStart).inDays;
      final newSelectedDate = newWeekStart.add(Duration(days: diff));

      add(LoadAvailability(newWeekStart, preselectedDate: newSelectedDate));
    }
  }

  Future<void> _onToggleDayStatus(
    ToggleDayStatus event,
    Emitter<AvailabilityState> emit,
  ) async {
    if (state is AvailabilityLoaded) {
      final currentState = state as AvailabilityLoaded;
      
      final newDay = event.day.copyWith(isAvailable: !event.day.isAvailable);
      final updatedDays = currentState.days.map((d) {
        return d.date == event.day.date ? newDay : d;
      }).toList();

      // Optimistic update
      emit(currentState.copyWith(
        days: updatedDays,
        clearSuccessMessage: true,
      ));

      try {
        await updateDayAvailability(UpdateDayAvailabilityParams(newDay));
        // Success feedback
        if (state is AvailabilityLoaded) {
           emit((state as AvailabilityLoaded).copyWith(successMessage: 'Availability updated'));
        }
      } catch (e) {
        // Revert
        if (state is AvailabilityLoaded) {
           emit((state as AvailabilityLoaded).copyWith(days: currentState.days));
        }
      }
    }
  }

  Future<void> _onToggleSlotStatus(
    ToggleSlotStatus event,
    Emitter<AvailabilityState> emit,
  ) async {
    if (state is AvailabilityLoaded) {
      final currentState = state as AvailabilityLoaded;

      final updatedSlots = event.day.slots.map((s) {
        if (s.id == event.slotId) {
          return s.copyWith(isAvailable: !s.isAvailable);
        }
        return s;
      }).toList();

      final newDay = event.day.copyWith(slots: updatedSlots);
      
      final updatedDays = currentState.days.map((d) {
        return d.date == event.day.date ? newDay : d;
      }).toList();

      // Optimistic update
      emit(currentState.copyWith(
        days: updatedDays,
        clearSuccessMessage: true,
      ));

      try {
        await updateDayAvailability(UpdateDayAvailabilityParams(newDay));
        // Success feedback
        if (state is AvailabilityLoaded) {
           emit((state as AvailabilityLoaded).copyWith(successMessage: 'Availability updated'));
        }
      } catch (e) {
         // Revert
         if (state is AvailabilityLoaded) {
            emit((state as AvailabilityLoaded).copyWith(days: currentState.days));
         }
      }
    }
  }

  Future<void> _onPerformQuickSet(
    PerformQuickSet event,
    Emitter<AvailabilityState> emit,
  ) async {
    if (state is AvailabilityLoaded) {
      final currentState = state as AvailabilityLoaded;
      
      emit(currentState.copyWith(
        isActionInProgress: true,
        clearSuccessMessage: true,
      ));
      
      try {
        final newDays = await applyQuickSet(
            ApplyQuickSetParams(currentState.currentWeekStart, event.type));
        
        emit(currentState.copyWith(
          days: newDays,
          isActionInProgress: false,
          successMessage: 'Availability updated',
        ));
      } catch (e) {
        emit(currentState.copyWith(
          isActionInProgress: false,
          // Could set error message here if we had a field for it, or emit AvailabilityError
          // But emitting AvailabilityError would replace the whole screen.
        ));
      }
    }
  }
}
