import 'dart:async';

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:intl/intl.dart';
import '../../../data/services/notification_orchestrator_service.dart';
import '../../../data/services/notification_event_producer_service.dart';
import '../../../data/services/myquran_sholat_service.dart';
import '../../../data/services/notification_service.dart';
import '../../../data/services/prayer_service.dart';
import '../../../data/services/location_service.dart';
import '../../../data/local/hive_boxes.dart';
import '../../../data/local/models/app_settings.dart';

/// Represents a single prayer time entry.
class PrayerTimeEntry {
  final String name;
  final String time; // "HH:mm"
  final bool isActive;
  PrayerTimeEntry({
    required this.name,
    required this.time,
    this.isActive = false,
  });
}

/// Full day prayer schedule from myQuran API.
class DaySchedule {
  final String cityName;
  final String province;
  final String date; // yyyy-MM-dd
  final String tanggal; // formatted date from API
  final Map<String, String>
      times; // {imsak, subuh, terbit, dhuha, dzuhur, ashar, maghrib, isya}

  DaySchedule({
    required this.cityName,
    required this.province,
    required this.date,
    required this.tanggal,
    required this.times,
  });

  /// Is this schedule for tomorrow?
  bool get isTomorrow {
    final todayStr = DateFormat('yyyy-MM-dd').format(DateTime.now());
    return date.compareTo(todayStr) > 0;
  }

  /// Get prayer time entries as a list.
  List<PrayerTimeEntry> get prayerList {
    final now = DateTime.now();
    final formatter = DateFormat('HH:mm');
    final currentTime = formatter.format(now);

    final prayers = [
      PrayerTimeEntry(name: 'Imsak', time: times['imsak'] ?? '-'),
      PrayerTimeEntry(name: 'Subuh', time: times['subuh'] ?? '-'),
      PrayerTimeEntry(name: 'Terbit', time: times['terbit'] ?? '-'),
      PrayerTimeEntry(name: 'Dhuha', time: times['dhuha'] ?? '-'),
      PrayerTimeEntry(name: 'Dzuhur', time: times['dzuhur'] ?? '-'),
      PrayerTimeEntry(name: 'Ashar', time: times['ashar'] ?? '-'),
      PrayerTimeEntry(name: 'Maghrib', time: times['maghrib'] ?? '-'),
      PrayerTimeEntry(name: 'Isya', time: times['isya'] ?? '-'),
    ];

    // Find the next prayer
    int activeIndex = -1;
    if (isTomorrow) {
      // User specifically requested to show tomorrow's Subuh as upcoming
      activeIndex = 1; // 0=Imsak, 1=Subuh
    } else {
      for (int i = 0; i < prayers.length; i++) {
        if (prayers[i].time != '-' &&
            prayers[i].time.compareTo(currentTime) > 0) {
          activeIndex = i;
          break;
        }
      }
    }

    if (activeIndex >= 0) {
      prayers[activeIndex] = PrayerTimeEntry(
        name: prayers[activeIndex].name,
        time: prayers[activeIndex].time,
        isActive: true,
      );
    }

    return prayers;
  }

  /// Get the next prayer name and time.
  PrayerTimeEntry? get nextPrayer {
    final list = prayerList;
    for (final p in list) {
      if (p.isActive) return p;
    }
    // If none active and it's today, all prayers have passed
    return null;
  }
}

/// Default Jakarta city ID from myQuran API.
const _defaultCityId = '58a2fc6ed39fd083f55d4182bf88826d';

/// Provider for the user's selected city ID (stored in Hive settings).
final selectedCityIdProvider = StateProvider<String>((ref) {
  final box = Hive.box<AppSettings>(HiveBoxes.settings);
  final settings = box.get('default');
  final stored = settings?.lastCityName ?? '';
  if (stored.contains('|')) {
    return stored.split('|').last;
  }
  return _defaultCityId;
});

/// Provider for today's prayer times using myQuran API.
final prayerTimesProvider = FutureProvider<DaySchedule?>((ref) async {
  final cityId = ref.watch(selectedCityIdProvider);
  final today = DateFormat('yyyy-MM-dd').format(DateTime.now());

  DaySchedule? schedule;

  // Try API first
  final jadwal =
      await MyQuranSholatService.instance.getDailySchedule(cityId, today);

  if (jadwal != null) {
    final cityInfo = await MyQuranSholatService.instance.getCityInfo(cityId);
    schedule = DaySchedule(
      cityName: cityInfo?['kabko'] ?? 'Jakarta',
      province: cityInfo?['prov'] ?? 'DKI Jakarta',
      date: today,
      tanggal: jadwal['tanggal'] ?? today,
      times: jadwal,
    );
  }

  // Check if all prayers today have passed
  if (schedule != null && !schedule.isTomorrow && schedule.nextPrayer == null) {
    // All prayers passed, fetch tomorrow's schedule
    final tomorrow = DateTime.now().add(const Duration(days: 1));
    final tomorrowStr = DateFormat('yyyy-MM-dd').format(tomorrow);

    final tmrwJadwal = await MyQuranSholatService.instance
        .getDailySchedule(cityId, tomorrowStr);

    if (tmrwJadwal != null) {
      final cityInfo = await MyQuranSholatService.instance.getCityInfo(cityId);
      schedule = DaySchedule(
        cityName: cityInfo?['kabko'] ?? 'Jakarta',
        province: cityInfo?['prov'] ?? 'DKI Jakarta',
        date: tomorrowStr,
        tanggal: tmrwJadwal['tanggal'] ?? tomorrowStr,
        times: tmrwJadwal,
      );
    }
  }

  if (schedule != null) {
    unawaited(_syncAdhanNotifications(cityId, schedule));
    return schedule;
  }

  // Fallback to adhan package
  final position = await LocationService.instance.getCurrentLocation();
  final lat = position?.latitude ?? -6.2088;
  final lng = position?.longitude ?? 106.8456;
  final locationUnavailable = position == null;

  final result =
      PrayerService.instance.getPrayerTimes(lat, lng, DateTime.now());
  final timeFormat = DateFormat('HH:mm');
  final fallbackSchedule = DaySchedule(
    cityName: 'Jakarta',
    province: 'DKI Jakarta',
    date: today,
    tanggal: DateFormat('EEEE, dd/MM/yyyy').format(DateTime.now()),
    times: {
      'imsak':
          timeFormat.format(result.fajr.subtract(const Duration(minutes: 10))),
      'subuh': timeFormat.format(result.fajr),
      'terbit': timeFormat.format(result.sunrise),
      'dhuha':
          timeFormat.format(result.sunrise.add(const Duration(minutes: 15))),
      'dzuhur': timeFormat.format(result.dhuhr),
      'ashar': timeFormat.format(result.asr),
      'maghrib': timeFormat.format(result.maghrib),
      'isya': timeFormat.format(result.isha),
    },
  );
  unawaited(
    NotificationEventProducerService.instance.emitScheduleFallback(
      settings: Hive.box<AppSettings>(HiveBoxes.settings).get('default') ??
          AppSettings(),
      cityId: cityId,
      locationUnavailable: locationUnavailable,
    ),
  );
  unawaited(_syncAdhanNotifications(cityId, fallbackSchedule));
  return fallbackSchedule;
});

Future<void> _syncAdhanNotifications(
    String cityId, DaySchedule schedule) async {
  try {
    final settingsBox = Hive.box<AppSettings>(HiveBoxes.settings);
    final settings = settingsBox.get('default') ?? AppSettings();
    final adhanEnabled = settings.adhanEnabled.values.any((v) => v);

    if (adhanEnabled) {
      final permissionStatus =
          await NotificationService.instance.getPermissionStatus();
      await NotificationEventProducerService.instance
          .emitPermissionWarningsIfNeeded(
        settings: settings,
        permissionStatus: permissionStatus,
      );
    }

    final schedulesByDate = <String, Map<String, String>>{};
    final today = DateTime.now();
    final startDate = DateTime(today.year, today.month, today.day);
    final endDate = startDate.add(const Duration(days: 35));

    final monthKeys = <String>{
      DateFormat('yyyy-MM').format(startDate),
      DateFormat('yyyy-MM').format(endDate),
    };

    for (final monthKey in monthKeys) {
      final monthly = await MyQuranSholatService.instance
          .getMonthlySchedule(cityId, monthKey);
      for (final entry in monthly.entries) {
        final date = DateTime.tryParse(entry.key);
        if (date == null) continue;
        final normalized = DateTime(date.year, date.month, date.day);
        if (normalized.isBefore(startDate) || normalized.isAfter(endDate)) {
          continue;
        }
        schedulesByDate[entry.key] = entry.value;
      }
    }

    if (schedulesByDate.isEmpty) {
      schedulesByDate[schedule.date] = schedule.times;
      final baseDate = DateTime.tryParse(schedule.date);
      if (baseDate != null) {
        final nextDate = DateFormat('yyyy-MM-dd')
            .format(baseDate.add(const Duration(days: 1)));
        final nextSchedule = await MyQuranSholatService.instance
            .getDailySchedule(cityId, nextDate);
        if (nextSchedule != null) {
          schedulesByDate[nextDate] = nextSchedule;
        }
      }
    }

    await NotificationService.instance.syncPrayerNotifications(
      cityId: cityId,
      adhanEnabled: settings.adhanEnabled,
      iqamahOffset: settings.iqamahOffset,
      schedulesByDate: schedulesByDate,
      reportReminderEnabled: settings.shalatReportReminderEnabled,
      reportReminderDelayMinutes: settings.shalatReportReminderDelayMinutes,
      reportReminderRepeatCount: settings.shalatReportReminderRepeatCount,
      reportReminderRepeatIntervalMinutes:
          settings.shalatReportReminderRepeatIntervalMinutes,
    );
    await NotificationService.instance.syncHabitNotifications(
      settings: settings,
    );
    await NotificationOrchestratorService.instance.runPassivePass(
      settings: settings,
    );
  } catch (_) {
    // Don't block UI when scheduling notifications fails.
    unawaited(
      NotificationEventProducerService.instance.emitNotificationSyncFailed(
        settings: Hive.box<AppSettings>(HiveBoxes.settings).get('default') ??
            AppSettings(),
        cityId: cityId,
      ),
    );
  }
}

/// Provider for monthly prayer schedule (for Imsakiyah screen).
final monthlyScheduleProvider =
    FutureProvider.family<Map<String, Map<String, String>>, String>(
        (ref, month) async {
  final cityId = ref.watch(selectedCityIdProvider);
  return MyQuranSholatService.instance.getMonthlySchedule(cityId, month);
});

/// Provider for current city name.
final cityNameProvider = FutureProvider<String>((ref) async {
  final box = Hive.box<AppSettings>(HiveBoxes.settings);
  final settings = box.get('default');
  final stored = settings?.lastCityName ?? '';
  if (stored.contains('|')) {
    return stored.split('|').first;
  }

  final cityId = ref.watch(selectedCityIdProvider);
  final info = await MyQuranSholatService.instance.getCityInfo(cityId);
  if (info != null) {
    return '${info['kabko']}, ${info['prov']}';
  }
  return 'Kota Jakarta, DKI Jakarta';
});
