import 'dart:async';
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:uuid/uuid.dart';
import 'package:intl/intl.dart';
import '../models/subscription_model.dart';
import '../services/notification_service.dart';
import '../services/exchange_rate_service.dart';
import '../services/currency_util.dart';
import 'category_provider.dart';
import '../l10n/app_localizations.dart';
import '../navigator_key.dart';

class SubscriptionProvider extends ChangeNotifier {
  late Box<SubscriptionModel> _subscriptionBox;
  List<SubscriptionModel> _subscriptions = [];
  bool _isLoading = true;

  List<SubscriptionModel> get subscriptions => _subscriptions;
  bool get isLoading => _isLoading;

  double get totalMonthlyExpense {
    final exchangeRateService = ExchangeRateService();
    final rate = exchangeRateService.cachedUsdToKrwRate ??
        ExchangeRateService.DEFAULT_USD_TO_KRW_RATE;

    final total = _subscriptions.fold(
      0.0,
      (sum, subscription) {
        final price = subscription.currentPrice;
        if (subscription.currency == 'USD') {
          debugPrint('[SubscriptionProvider] ${subscription.serviceName}: '
              '\$$price × ₩$rate = ₩${price * rate}');
          return sum + (price * rate);
        }
        debugPrint(
            '[SubscriptionProvider] ${subscription.serviceName}: ₩$price');
        return sum + price;
      },
    );

    debugPrint('[SubscriptionProvider] totalMonthlyExpense 계산 완료: '
        '${_subscriptions.length}개 구독, 총액 ₩$total');
    return total;
  }

  /// 월간 총 비용을 반환합니다.
  double getTotalMonthlyCost() {
    return totalMonthlyExpense;
  }

  /// 이벤트로 인한 총 절약액을 반환합니다.
  double get totalEventSavings {
    return _subscriptions.fold(
      0.0,
      (sum, subscription) => sum + subscription.eventSavings,
    );
  }

  /// 현재 이벤트 중인 구독 목록을 반환합니다.
  List<SubscriptionModel> get activeEventSubscriptions {
    return _subscriptions.where((sub) => sub.isCurrentlyInEvent).toList();
  }

  Future<void> init() async {
    try {
      _isLoading = true;
      notifyListeners();

      // 환율 정보 미리 로드
      await ExchangeRateService().getUsdToKrwRate();

      _subscriptionBox = await Hive.openBox<SubscriptionModel>('subscriptions');
      await refreshSubscriptions();

      // categoryId 마이그레이션
      await _migrateCategoryIds();

      // 앱 시작 시 이벤트 상태 확인
      await checkAndUpdateEventStatus();

      _isLoading = false;
      notifyListeners();
    } catch (e) {
      debugPrint('구독 초기화 중 오류 발생: $e');
      _isLoading = false;
      notifyListeners();
      rethrow;
    }
  }

  Future<void> refreshSubscriptions() async {
    try {
      _subscriptions = _subscriptionBox.values.toList()
        ..sort((a, b) => a.nextBillingDate.compareTo(b.nextBillingDate));

      debugPrint('[SubscriptionProvider] refreshSubscriptions 완료: '
          '${_subscriptions.length}개 구독, '
          '총 월간 지출: ${totalMonthlyExpense.toStringAsFixed(2)}');

      notifyListeners();
    } catch (e) {
      debugPrint('구독 목록 새로고침 중 오류 발생: $e');
      rethrow;
    }
  }

  Future<void> _reschedulePaymentNotifications() async {
    try {
      await NotificationService.reschedulAllNotifications(_subscriptions);
    } catch (e) {
      debugPrint('결제 알림 재예약 중 오류 발생: $e');
    }
  }

  Future<void> addSubscription({
    required String serviceName,
    required double monthlyCost,
    required String billingCycle,
    required DateTime nextBillingDate,
    String? websiteUrl,
    String? categoryId,
    String? paymentCardId,
    bool isAutoDetected = false,
    int repeatCount = 1,
    DateTime? lastPaymentDate,
    String currency = 'KRW',
    bool isEventActive = false,
    DateTime? eventStartDate,
    DateTime? eventEndDate,
    double? eventPrice,
  }) async {
    try {
      final subscription = SubscriptionModel(
        id: const Uuid().v4(),
        serviceName: serviceName,
        monthlyCost: monthlyCost,
        billingCycle: billingCycle,
        nextBillingDate: nextBillingDate,
        websiteUrl: websiteUrl,
        categoryId: categoryId,
        paymentCardId: paymentCardId,
        isAutoDetected: isAutoDetected,
        repeatCount: repeatCount,
        lastPaymentDate: lastPaymentDate,
        currency: currency,
        isEventActive: isEventActive,
        eventStartDate: eventStartDate,
        eventEndDate: eventEndDate,
        eventPrice: eventPrice,
      );

      await _subscriptionBox.put(subscription.id, subscription);
      await refreshSubscriptions();

      // 이벤트가 활성화된 경우 알림 스케줄 재설정
      if (isEventActive && eventEndDate != null) {
        await _scheduleEventEndNotification(subscription);
      }

      await _reschedulePaymentNotifications();
    } catch (e) {
      debugPrint('구독 추가 중 오류 발생: $e');
      rethrow;
    }
  }

  Future<void> updateSubscription(SubscriptionModel subscription) async {
    try {
      debugPrint('[SubscriptionProvider] updateSubscription 호출됨: '
          '${subscription.serviceName}, '
          '금액: ${subscription.monthlyCost} ${subscription.currency}, '
          '현재가격: ${subscription.currentPrice} ${subscription.currency}');

      await _subscriptionBox.put(subscription.id, subscription);
      debugPrint('[SubscriptionProvider] Hive에 저장 완료');

      // 이벤트 관련 알림 업데이트
      if (subscription.isEventActive && subscription.eventEndDate != null) {
        await _scheduleEventEndNotification(subscription);
      } else {
        // 이벤트가 비활성화된 경우 이벤트 종료 알림 취소
        await NotificationService.cancelNotification(
          '${subscription.id}_event_end'.hashCode,
        );
      }

      await refreshSubscriptions();

      debugPrint('[SubscriptionProvider] 구독 업데이트 완료, '
          '현재 총 월간 지출: ${totalMonthlyExpense.toStringAsFixed(2)}');
      notifyListeners();

      await _reschedulePaymentNotifications();
    } catch (e) {
      debugPrint('구독 업데이트 중 오류 발생: $e');
      rethrow;
    }
  }

  Future<void> deleteSubscription(String id) async {
    try {
      await _subscriptionBox.delete(id);
      await refreshSubscriptions();

      await _reschedulePaymentNotifications();
    } catch (e) {
      debugPrint('구독 삭제 중 오류 발생: $e');
      rethrow;
    }
  }

  Future<void> clearAllSubscriptions() async {
    _isLoading = true;
    notifyListeners();

    try {
      // 모든 알림 취소
      for (var subscription in _subscriptions) {
        await NotificationService.cancelSubscriptionNotification(subscription);
      }

      // 모든 데이터 삭제
      await _subscriptionBox.clear();
      _subscriptions = [];

      notifyListeners();
    } catch (e) {
      debugPrint('모든 구독 정보 삭제 중 오류 발생: $e');
      rethrow;
    } finally {
      _isLoading = false;
      notifyListeners();

      await _reschedulePaymentNotifications();
    }
  }

  /// 이벤트 종료 알림을 스케줄링합니다.
  Future<void> _scheduleEventEndNotification(
      SubscriptionModel subscription) async {
    if (subscription.eventEndDate != null &&
        subscription.eventEndDate!.isAfter(DateTime.now())) {
      final ctx = navigatorKey.currentContext;
      final loc = ctx != null ? AppLocalizations.of(ctx) : null;
      await NotificationService.scheduleNotification(
        id: '${subscription.id}_event_end'.hashCode,
        title: loc?.eventEndNotificationTitle ?? 'Event end notification',
        body: loc?.eventEndNotificationBody(subscription.serviceName) ??
            "${subscription.serviceName}'s discount event has ended.",
        scheduledDate: subscription.eventEndDate!,
        channelId: NotificationService.expirationChannelId,
      );
    }
  }

  /// 모든 구독의 이벤트 상태를 확인하고 업데이트합니다.
  Future<void> checkAndUpdateEventStatus() async {
    bool hasChanges = false;

    for (var subscription in _subscriptions) {
      // 이벤트가 종료되었지만 아직 활성화되어 있는 경우
      if (subscription.isEventActive &&
          subscription.eventEndDate != null &&
          subscription.eventEndDate!.isBefore(DateTime.now())) {
        subscription.isEventActive = false;
        await _subscriptionBox.put(subscription.id, subscription);
        hasChanges = true;
      }
    }

    if (hasChanges) {
      await refreshSubscriptions();
    }
  }

  /// 총 월간 지출을 계산합니다. (로케일별 기본 통화로 환산)
  Future<double> calculateTotalExpense({
    String? locale,
    List<SubscriptionModel>? subset,
  }) async {
    final targetSubscriptions = subset ?? _subscriptions;
    if (targetSubscriptions.isEmpty) return 0.0;

    // locale이 제공되지 않으면 현재 로케일 사용
    final targetCurrency =
        locale != null ? CurrencyUtil.getDefaultCurrency(locale) : 'KRW'; // 기본값

    debugPrint('[calculateTotalExpense] 계산 시작 - 타겟 통화: $targetCurrency, '
        '대상 구독: ${targetSubscriptions.length}개');
    double total = 0.0;

    for (final subscription in targetSubscriptions) {
      final currentPrice = subscription.currentPrice;
      debugPrint('[calculateTotalExpense] ${subscription.serviceName}: '
          '$currentPrice ${subscription.currency} (이벤트 적용: ${subscription.isCurrentlyInEvent})');

      final converted = await ExchangeRateService().convertBetweenCurrencies(
        currentPrice,
        subscription.currency,
        targetCurrency,
      );

      total += converted ?? currentPrice;
    }

    debugPrint('[calculateTotalExpense] 총 지출 계산 완료: $total '
        '$targetCurrency (대상 ${targetSubscriptions.length}개)');
    return total;
  }

  /// 최근 6개월의 월별 지출 데이터를 반환합니다. (로케일별 기본 통화로 환산)
  Future<List<Map<String, dynamic>>> getMonthlyExpenseData({
    String? locale,
    List<SubscriptionModel>? subset,
  }) async {
    final now = DateTime.now();
    final List<Map<String, dynamic>> monthlyData = [];
    final targetSubscriptions = subset ?? _subscriptions;

    // locale이 제공되지 않으면 현재 로케일 사용
    final targetCurrency =
        locale != null ? CurrencyUtil.getDefaultCurrency(locale) : 'KRW'; // 기본값

    // 최근 6개월 데이터 생성
    for (int i = 5; i >= 0; i--) {
      final month = DateTime(now.year, now.month - i, 1);
      double monthTotal = 0.0;

      // 현재 월인지 확인
      final isCurrentMonth =
          (month.year == now.year && month.month == now.month);

      if (isCurrentMonth) {
        debugPrint(
            '[getMonthlyExpenseData] 현재 월(${month.year}-${month.month}) 계산 중...');
      }

      // 해당 월에 활성화된 구독 계산
      for (final subscription in targetSubscriptions) {
        if (isCurrentMonth) {
          // 현재 월인 경우: 모든 활성 구독 포함 (calculateTotalExpense와 동일하게)
          final cost = subscription.currentPrice;
          debugPrint(
              '[getMonthlyExpenseData] 현재 월 - ${subscription.serviceName}: '
              '$cost ${subscription.currency} (이벤트 적용: ${subscription.isCurrentlyInEvent})');

          // 통화 변환
          final converted =
              await ExchangeRateService().convertBetweenCurrencies(
            cost,
            subscription.currency,
            targetCurrency,
          );

          monthTotal += converted ?? cost;
        } else {
          // 과거 월인 경우: 기존 로직 유지
          // 구독이 해당 월에 활성화되어 있었는지 확인
          final subscriptionStartDate = subscription.nextBillingDate.subtract(
            Duration(days: _getBillingCycleDays(subscription.billingCycle)),
          );

          if (subscriptionStartDate
                  .isBefore(DateTime(month.year, month.month + 1, 1)) &&
              subscription.nextBillingDate.isAfter(month)) {
            // 해당 월의 비용 계산 (이벤트 가격 고려)
            double cost;

            if (subscription.isEventActive &&
                subscription.eventStartDate != null &&
                subscription.eventEndDate != null &&
                // 이벤트 기간과 해당 월이 겹치는지 확인
                subscription.eventStartDate!
                    .isBefore(DateTime(month.year, month.month + 1, 1)) &&
                subscription.eventEndDate!.isAfter(month)) {
              cost = subscription.eventPrice ?? subscription.monthlyCost;
            } else {
              cost = subscription.monthlyCost;
            }

            // 통화 변환
            final converted =
                await ExchangeRateService().convertBetweenCurrencies(
              cost,
              subscription.currency,
              targetCurrency,
            );

            monthTotal += converted ?? cost;
          }
        }
      }

      if (isCurrentMonth) {
        debugPrint(
            '[getMonthlyExpenseData] 현재 월(${_getMonthLabel(month, locale ?? 'en')}) 총 지출: $monthTotal $targetCurrency');
      }

      monthlyData.add({
        'month': month,
        'totalExpense': monthTotal,
        'monthName': _getMonthLabel(month, locale ?? 'en'),
      });
    }

    return monthlyData;
  }

  /// 이벤트로 인한 총 절약액을 계산합니다.
  double calculateTotalSavings() {
    // 이미 존재하는 totalEventSavings getter를 사용
    return totalEventSavings;
  }

  /// 결제 주기를 일 단위로 변환합니다.
  int _getBillingCycleDays(String billingCycle) {
    switch (billingCycle) {
      case 'monthly':
        return 30;
      case 'yearly':
        return 365;
      case 'weekly':
        return 7;
      case 'quarterly':
        return 90;
      default:
        return 30;
    }
  }

  /// 월 라벨을 생성합니다.
  String _getMonthLabel(DateTime month, String locale) {
    if (locale == 'ko') {
      // 한국어는 기존 형식 유지 (1월, 2월 등)
      return '${month.month}월';
    } else if (locale == 'ja') {
      // 일본어
      return '${month.month}月';
    } else if (locale == 'zh') {
      // 중국어
      return '${month.month}月';
    } else {
      // 영어 및 기타 언어는 약식 월 이름 사용
      return DateFormat('MMM', locale).format(month);
    }
  }

  /// categoryId가 없는 기존 구독들에 대해 자동으로 카테고리 할당
  Future<void> _migrateCategoryIds() async {
    debugPrint('❎ CategoryId 마이그레이션 시작...');

    final categoryProvider = CategoryProvider();
    await categoryProvider.init();
    final categories = categoryProvider.categories;

    int migratedCount = 0;

    for (var subscription in _subscriptions) {
      if (subscription.categoryId == null) {
        final serviceName = subscription.serviceName.toLowerCase();
        String? categoryId;

        debugPrint('🔍 ${subscription.serviceName} 카테고리 매칭 시도...');

        // OTT 서비스
        if (serviceName.contains('netflix') ||
            serviceName.contains('youtube') ||
            serviceName.contains('disney') ||
            serviceName.contains('왓차') ||
            serviceName.contains('티빙') ||
            serviceName.contains('디즈니') ||
            serviceName.contains('넷플릭스')) {
          categoryId = categories
              .firstWhere(
                (cat) => cat.name == 'OTT 서비스',
                orElse: () => categories.first,
              )
              .id;
        }
        // 음악 서비스
        else if (serviceName.contains('spotify') ||
            serviceName.contains('apple music') ||
            serviceName.contains('멜론') ||
            serviceName.contains('지니') ||
            serviceName.contains('플로') ||
            serviceName.contains('벡스')) {
          categoryId = categories
              .firstWhere(
                (cat) => cat.name == 'music',
                orElse: () => categories.first,
              )
              .id;
        }
        // AI 서비스
        else if (serviceName.contains('chatgpt') ||
            serviceName.contains('claude') ||
            serviceName.contains('midjourney') ||
            serviceName.contains('copilot')) {
          categoryId = categories
              .firstWhere(
                (cat) => cat.name == 'aiService',
                orElse: () => categories.first,
              )
              .id;
        }
        // 프로그래밍/개발
        else if (serviceName.contains('github') ||
            serviceName.contains('intellij') ||
            serviceName.contains('webstorm') ||
            serviceName.contains('jetbrains')) {
          categoryId = categories
              .firstWhere(
                (cat) => cat.name == 'programming',
                orElse: () => categories.first,
              )
              .id;
        }
        // 오피스/협업 툴
        else if (serviceName.contains('notion') ||
            serviceName.contains('microsoft') ||
            serviceName.contains('office') ||
            serviceName.contains('slack') ||
            serviceName.contains('figma') ||
            serviceName.contains('icloud') ||
            serviceName.contains('아이클라우드')) {
          categoryId = categories
              .firstWhere(
                (cat) => cat.name == 'collaborationOffice',
                orElse: () => categories.first,
              )
              .id;
        }
        // 기타 서비스 (기본값)
        else {
          categoryId = categories
              .firstWhere(
                (cat) => cat.name == 'other',
                orElse: () => categories.first,
              )
              .id;
        }

        subscription.categoryId = categoryId;
        await subscription.save();
        migratedCount++;
        final categoryName =
            categories.firstWhere((cat) => cat.id == categoryId).name;
        debugPrint('✅ ${subscription.serviceName} → $categoryName');
      }
    }

    if (migratedCount > 0) {
      debugPrint('❎ 총 $migratedCount개의 구독에 categoryId 할당 완료');
      await refreshSubscriptions();
    } else {
      debugPrint('❎ 모든 구독이 이미 categoryId를 가지고 있습니다');
    }
  }
}
