import 'package:krow_data_connect/krow_data_connect.dart' hide AvailabilitySlot;
import 'package:krow_domain/krow_domain.dart';
import '../../domain/repositories/availability_repository.dart';
import 'package:intl/intl.dart';

/// Implementation of [AvailabilityRepository].
/// 
/// Uses [StaffRepositoryMock] from data_connect to fetch and store data.
class AvailabilityRepositoryImpl implements AvailabilityRepository {
  final StaffRepositoryMock _dataSource;

  // Mock User ID - in real app invoke AuthUseCase to get current user
  final String _userId = 'mock_user_123';

  static const List<Map<String, String>> _slotDefinitions = [
    {
      'id': 'morning',
      'label': 'Morning',
      'timeRange': '4:00 AM - 12:00 PM',
    },
    {
      'id': 'afternoon',
      'label': 'Afternoon',
      'timeRange': '12:00 PM - 6:00 PM',
    },
    {
      'id': 'evening',
      'label': 'Evening',
      'timeRange': '6:00 PM - 12:00 AM',
    },
  ];

  AvailabilityRepositoryImpl({StaffRepositoryMock? dataSource})
      : _dataSource = dataSource ?? StaffRepositoryMock();

  @override
  Future<List<DayAvailability>> getAvailability(
      DateTime start, DateTime end) async {
    final rawData = await _dataSource.getAvailability(_userId, start, end);
    final List<DayAvailability> days = [];

    // Loop through each day in range
    for (int i = 0; i <= end.difference(start).inDays; i++) {
      final date = start.add(Duration(days: i));
      final dateKey = DateFormat('yyyy-MM-dd').format(date);
      
      final dayData = rawData[dateKey];
      
      if (dayData != null) {
        days.add(_mapFromData(date, dayData));
      } else {
        // Default: Available M-F, Not Sat-Sun (matching prototype logic)
        final isWeekend = date.weekday == DateTime.saturday || date.weekday == DateTime.sunday;
        // Prototype: Sat/Sun false
        
        days.add(DayAvailability(
          date: date,
          isAvailable: !isWeekend,
          slots: _generateDefaultSlots(isEnabled: !isWeekend),
        ));
      }
    }
    return days;
  }

  @override
  Future<DayAvailability> updateDayAvailability(
      DayAvailability availability) async {
    final dateKey = DateFormat('yyyy-MM-dd').format(availability.date);
    final data = _mapToData(availability);
    
    await _dataSource.updateAvailability(_userId, dateKey, data);
    return availability;
  }

  @override
  Future<List<DayAvailability>> applyQuickSet(
      DateTime start, DateTime end, String type) async {
    final List<DayAvailability> updatedDays = [];
    
    for (int i = 0; i <= end.difference(start).inDays; i++) {
      final date = start.add(Duration(days: i));
      bool isAvailable = false;
      
      switch (type) {
        case 'all':
          isAvailable = true;
          break;
        case 'weekdays':
          isAvailable = date.weekday != DateTime.saturday && date.weekday != DateTime.sunday;
          break;
        case 'weekends':
          isAvailable = date.weekday == DateTime.saturday || date.weekday == DateTime.sunday;
          break;
        case 'clear':
          isAvailable = false;
          break;
      }
      
      // Keep existing slot preferences, just toggle main switch? 
      // Or reset slots too? Prototype behavior: just sets map[day] = bool. 
      // But it implies slots are active if day is active?
      // For now, allow slots to be default true if day is enabled.
      
      final day = DayAvailability(
        date: date,
        isAvailable: isAvailable,
        slots: _generateDefaultSlots(isEnabled: isAvailable),
      );
      
      await updateDayAvailability(day);
      updatedDays.add(day);
    }
    return updatedDays;
  }

  // --- Helpers ---

  List<AvailabilitySlot> _generateDefaultSlots({bool isEnabled = true}) {
    return _slotDefinitions.map((def) {
      return AvailabilitySlot(
        id: def['id']!,
        label: def['label']!,
        timeRange: def['timeRange']!,
        isAvailable: true, // Default slots to true
      );
    }).toList();
  }

  DayAvailability _mapFromData(DateTime date, Map<String, dynamic> data) {
    final isAvailable = data['isAvailable'] as bool? ?? false;
    final Map<String, dynamic> slotsMap = data['slots'] ?? {};

    final slots = _slotDefinitions.map((def) {
      final slotId = def['id']!;
      final slotEnabled = slotsMap[slotId] as bool? ?? true; // Default true if not stored
      
      return AvailabilitySlot(
        id: slotId,
        label: def['label']!,
        timeRange: def['timeRange']!,
        isAvailable: slotEnabled,
      );
    }).toList();

    return DayAvailability(
      date: date,
      isAvailable: isAvailable,
      slots: slots,
    );
  }

  Map<String, dynamic> _mapToData(DayAvailability day) {
    Map<String, bool> slotsMap = {};
    for (var slot in day.slots) {
      slotsMap[slot.id] = slot.isAvailable;
    }

    return {
      'isAvailable': day.isAvailable,
      'slots': slotsMap,
    };
  }
}
