import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:timezone/timezone.dart' as tz;
import 'package:timezone/data/latest_all.dart' as tz;
import 'package:flutter/foundation.dart';
import 'dart:io' show Platform;
import '../models/subscription_model.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import '../navigator_key.dart';
import '../l10n/app_localizations.dart';
import '../services/currency_util.dart';

class NotificationService {
  static final FlutterLocalNotificationsPlugin _notifications =
      FlutterLocalNotificationsPlugin();
  static const _secureStorage = FlutterSecureStorage();

  static const _notificationEnabledKey = 'notification_enabled';
  static const _paymentNotificationEnabledKey = 'payment_notification_enabled';
  static const _reminderDaysKey = 'reminder_days';
  static const _reminderHourKey = 'reminder_hour';
  static const _reminderMinuteKey = 'reminder_minute';
  static const _dailyReminderKey = 'daily_reminder_enabled';
  static const int _maxDailyReminderSlots = 7;
  static const String _paymentPayloadPrefix = 'payment:';
  static const String _paymentChannelId = 'subscription_channel_v2';
  static const String _expirationChannelId = 'expiration_channel_v2';

  static String get paymentChannelId => _paymentChannelId;
  static String get expirationChannelId => _expirationChannelId;

  static String _paymentPayload(String subscriptionId) =>
      '$_paymentPayloadPrefix$subscriptionId';

  static bool _matchesPaymentPayload(String? payload) =>
      payload != null && payload.startsWith(_paymentPayloadPrefix);

  static String? _subscriptionIdFromPaymentPayload(String? payload) =>
      _matchesPaymentPayload(payload)
          ? payload!.substring(_paymentPayloadPrefix.length)
          : null;

  // 초기화 상태를 추적하기 위한 플래그
  static bool _initialized = false;

  // 웹 플랫폼 여부 확인 (웹에서는 flutter_local_notifications가 지원되지 않음)
  static bool get _isWeb => kIsWeb;

  static const AndroidNotificationChannel channel = AndroidNotificationChannel(
    'subscription_channel',
    'Subscription Notifications',
    description: 'Channel for subscription reminders',
    importance: Importance.high,
    enableVibration: true,
  );

  // 알림 초기화
  static Future<void> init() async {
    try {
      // 웹 플랫폼인 경우 초기화 건너뛰기
      if (_isWeb) {
        debugPrint('웹 플랫폼에서는 로컬 알림이 지원되지 않습니다.');
        return;
      }

      tz.initializeTimeZones();
      try {
        tz.setLocalLocation(tz.getLocation('Asia/Seoul'));
      } catch (e) {
        // 타임존 찾기 실패시 UTC 사용
        tz.setLocalLocation(tz.UTC);
        debugPrint('타임존 설정 실패, UTC 사용: $e');
      }
      const androidSettings =
          AndroidInitializationSettings('@mipmap/ic_launcher');
      const iosSettings = DarwinInitializationSettings();
      const initSettings =
          InitializationSettings(android: androidSettings, iOS: iosSettings);

      await _notifications.initialize(initSettings);

      // Android 채널을 선제적으로 생성하여 중요도/진동이 확실히 적용되도록 함
      if (Platform.isAndroid) {
        final androidImpl =
            _notifications.resolvePlatformSpecificImplementation<
                AndroidFlutterLocalNotificationsPlugin>();
        if (androidImpl != null) {
          try {
            await androidImpl
                .createNotificationChannel(const AndroidNotificationChannel(
              _paymentChannelId,
              'Subscription Notifications',
              description: 'Channel for subscription reminders',
              importance: Importance.high,
            ));
            await androidImpl
                .createNotificationChannel(const AndroidNotificationChannel(
              _expirationChannelId,
              'Expiration Notifications',
              description: 'Channel for subscription expiration reminders',
              importance: Importance.high,
            ));
          } catch (e) {
            debugPrint('안드로이드 채널 생성 실패: $e');
          }
        }
      }
      _initialized = true;
      debugPrint('알림 서비스 초기화 완료');
    } catch (e) {
      _initialized = false;
      debugPrint('알림 서비스 초기화 실패: $e');
    }
  }

  static Future<bool> isNotificationEnabled() async {
    final value = await _secureStorage.read(key: _notificationEnabledKey);
    return value == 'true';
  }

  static Future<bool> isPaymentNotificationEnabled() async {
    final value =
        await _secureStorage.read(key: _paymentNotificationEnabledKey);
    return value == 'true';
  }

  static Future<void> setNotificationEnabled(bool value) async {
    await _secureStorage.write(
      key: _notificationEnabledKey,
      value: value.toString(),
    );
  }

  static Future<void> setPaymentNotificationEnabled(bool value) async {
    await _secureStorage.write(
      key: _paymentNotificationEnabledKey,
      value: value.toString(),
    );
  }

  // 알림 시점 설정 (1일전, 2일전, 3일전) 가져오기
  static Future<int> getReminderDays() async {
    final value = await _secureStorage.read(key: _reminderDaysKey);
    return value != null ? int.tryParse(value) ?? 3 : 3;
  }

  // 알림 시간 가져오기
  static Future<int> getReminderHour() async {
    final value = await _secureStorage.read(key: _reminderHourKey);
    return value != null ? int.tryParse(value) ?? 10 : 10;
  }

  static Future<int> getReminderMinute() async {
    final value = await _secureStorage.read(key: _reminderMinuteKey);
    return value != null ? int.tryParse(value) ?? 0 : 0;
  }

  // 반복 알림 설정 가져오기
  static Future<bool> isDailyReminderEnabled() async {
    final value = await _secureStorage.read(key: _dailyReminderKey);
    return value == 'true';
  }

  // 모든 구독의 알림 일정 다시 예약
  static Future<void> reschedulAllNotifications(
      List<SubscriptionModel> subscriptions) async {
    try {
      // 웹 플랫폼이거나 알림 초기화 실패한 경우 건너뛰기
      if (_isWeb || !_initialized) {
        debugPrint('웹 플랫폼이거나 알림 서비스가 초기화되지 않아 알림을 예약할 수 없습니다.');
        return;
      }

      final pendingRequests =
          await _notifications.pendingNotificationRequests();

      final isPaymentEnabled = await isPaymentNotificationEnabled();
      if (!isPaymentEnabled) {
        await _cancelOrphanedPaymentReminderNotifications(
          const <String>{},
          pendingRequests,
        );
        return;
      }

      final reminderDays = await getReminderDays();
      final reminderHour = await getReminderHour();
      final reminderMinute = await getReminderMinute();
      final isDailyReminder = await isDailyReminderEnabled();

      final activeSubscriptionIds =
          subscriptions.map((subscription) => subscription.id).toSet();

      for (final subscription in subscriptions) {
        await _cancelPaymentReminderNotificationsForSubscription(
          subscription,
          pendingRequests,
        );

        await schedulePaymentReminder(
          subscription: subscription,
          reminderDays: reminderDays,
          reminderHour: reminderHour,
          reminderMinute: reminderMinute,
          isDailyReminder: isDailyReminder,
        );
      }

      await _cancelOrphanedPaymentReminderNotifications(
        activeSubscriptionIds,
        pendingRequests,
      );
    } catch (e) {
      debugPrint('알림 일정 재설정 중 오류 발생: $e');
    }
  }

  static Future<void> _cancelPaymentReminderNotificationsForSubscription(
    SubscriptionModel subscription,
    List<PendingNotificationRequest> pendingRequests,
  ) async {
    final baseId = subscription.id.hashCode;
    final payload = _paymentPayload(subscription.id);

    final idsToCancel = <int>{};

    for (final request in pendingRequests) {
      final matchesPayload = request.payload == payload;
      final matchesIdPattern = request.id == baseId ||
          (request.id > baseId &&
              request.id <= baseId + _maxDailyReminderSlots);

      if (matchesPayload || matchesIdPattern) {
        idsToCancel.add(request.id);
      }
    }

    for (final id in idsToCancel) {
      try {
        await _notifications.cancel(id);
      } catch (e) {
        debugPrint('결제 알림 취소 중 오류 발생: $e');
      }
    }

    if (idsToCancel.isNotEmpty) {
      pendingRequests
          .removeWhere((request) => idsToCancel.contains(request.id));
    }
  }

  static Future<void> _cancelOrphanedPaymentReminderNotifications(
    Set<String> activeSubscriptionIds,
    List<PendingNotificationRequest> pendingRequests,
  ) async {
    final idsToCancel = <int>{};

    for (final request in pendingRequests) {
      final subscriptionId = _subscriptionIdFromPaymentPayload(request.payload);
      if (subscriptionId != null &&
          !activeSubscriptionIds.contains(subscriptionId)) {
        idsToCancel.add(request.id);
      }
    }

    for (final id in idsToCancel) {
      try {
        await _notifications.cancel(id);
      } catch (e) {
        debugPrint('고아 결제 알림 취소 중 오류 발생: $e');
      }
    }

    if (idsToCancel.isNotEmpty) {
      pendingRequests
          .removeWhere((request) => idsToCancel.contains(request.id));
    }
  }

  static Future<bool> requestPermission() async {
    // 웹 플랫폼인 경우 false 반환
    if (_isWeb) return false;

    // iOS 처리
    if (Platform.isIOS) {
      final iosImplementation =
          _notifications.resolvePlatformSpecificImplementation<
              IOSFlutterLocalNotificationsPlugin>();

      if (iosImplementation != null) {
        final granted = await iosImplementation.requestPermissions(
          alert: true,
          badge: true,
          sound: true,
        );
        return granted ?? false;
      }
    }

    // Android 처리
    if (Platform.isAndroid) {
      final androidImplementation =
          _notifications.resolvePlatformSpecificImplementation<
              AndroidFlutterLocalNotificationsPlugin>();

      if (androidImplementation != null) {
        final granted =
            await androidImplementation.requestNotificationsPermission();
        return granted ?? false;
      }
    }

    return false;
  }

  // 권한 상태 확인
  static Future<bool> checkPermission() async {
    // 웹 플랫폼인 경우 false 반환
    if (_isWeb) return false;

    // Android 처리
    if (Platform.isAndroid) {
      final androidImplementation =
          _notifications.resolvePlatformSpecificImplementation<
              AndroidFlutterLocalNotificationsPlugin>();

      if (androidImplementation != null) {
        // Android 13 이상에서만 권한 확인 필요
        final isEnabled = await androidImplementation.areNotificationsEnabled();
        return isEnabled ?? false;
      }
    }

    // iOS 처리
    if (Platform.isIOS) {
      final iosImplementation =
          _notifications.resolvePlatformSpecificImplementation<
              IOSFlutterLocalNotificationsPlugin>();

      if (iosImplementation != null) {
        final settings = await iosImplementation.checkPermissions();
        return settings?.isEnabled ?? false;
      }
    }

    return true; // 기본값
  }

  // Android: 정확 알람 권한 가능 여부 확인 (S+)
  static Future<bool> canScheduleExactAlarms() async {
    if (_isWeb) return false;
    if (Platform.isAndroid) {
      final android = _notifications.resolvePlatformSpecificImplementation<
          AndroidFlutterLocalNotificationsPlugin>();
      if (android != null) {
        final can = await android.canScheduleExactNotifications();
        return can ?? true; // 하위 버전은 true 간주
      }
    }
    return true;
  }

  // Android: 정확 알람 권한 요청 (Android 12+에서 설정 화면으로 이동)
  static Future<bool> requestExactAlarmsPermission() async {
    if (_isWeb) return false;
    if (Platform.isAndroid) {
      final android = _notifications.resolvePlatformSpecificImplementation<
          AndroidFlutterLocalNotificationsPlugin>();
      if (android != null) {
        final granted = await android.requestExactAlarmsPermission();
        return granted ?? false;
      }
    }
    return false;
  }

  static Future<AndroidScheduleMode> _resolveAndroidScheduleMode() async {
    if (_isWeb) {
      return AndroidScheduleMode.exactAllowWhileIdle;
    }

    if (Platform.isAndroid) {
      try {
        final canExact = await canScheduleExactAlarms();
        if (kDebugMode) {
          debugPrint(
              '[NotificationService] canScheduleExactAlarms result: $canExact');
        }
        if (!canExact) {
          if (kDebugMode) {
            debugPrint(
                '[NotificationService] exact alarm unavailable → use inexact mode');
          }
          return AndroidScheduleMode.inexactAllowWhileIdle;
        }
      } catch (e) {
        debugPrint('정확 알람 권한 확인 중 오류 발생: $e');
        return AndroidScheduleMode.inexactAllowWhileIdle;
      }
    }

    return AndroidScheduleMode.exactAllowWhileIdle;
  }

  // 알림 스케줄 설정
  static Future<void> scheduleNotification({
    required int id,
    required String title,
    required String body,
    required DateTime scheduledDate,
    String? payload,
    String? channelId,
  }) async {
    // 웹 플랫폼이거나 초기화되지 않은 경우 건너뛰기
    if (_isWeb || !_initialized) {
      debugPrint('알림 서비스가 초기화되지 않아 알림을 예약할 수 없습니다.');
      return;
    }

    try {
      final ctx = navigatorKey.currentContext;
      String channelName;
      if (channelId == _expirationChannelId) {
        channelName = ctx != null
            ? AppLocalizations.of(ctx).expirationReminder
            : 'Expiration Notifications';
      } else {
        channelName = ctx != null
            ? AppLocalizations.of(ctx).notifications
            : 'Subscription Notifications';
      }

      final effectiveChannelId = channelId ?? _paymentChannelId;

      final androidDetails = AndroidNotificationDetails(
        effectiveChannelId,
        channelName,
        channelDescription: channelName,
        importance: Importance.high,
        priority: Priority.high,
        autoCancel: false,
      );

      const iosDetails = DarwinNotificationDetails(
        presentAlert: true,
        presentBadge: true,
        presentSound: true,
      );

      // tz.local 초기화 확인 및 재시도
      tz.Location location;
      try {
        location = tz.local;
      } catch (e) {
        // tz.local이 초기화되지 않은 경우 재시도
        debugPrint('tz.local 초기화되지 않음, 재시도 중...');
        try {
          tz.setLocalLocation(tz.getLocation('Asia/Seoul'));
          location = tz.local;
        } catch (_) {
          // 그래도 실패하면 UTC 사용
          debugPrint('타임존 설정 실패, UTC 사용');
          tz.setLocalLocation(tz.UTC);
          location = tz.UTC;
        }
      }

      // 과거 시각 방지: 최소 1분 뒤로 조정
      final nowTz = tz.TZDateTime.now(location);
      var target = tz.TZDateTime.from(scheduledDate, location);
      if (!target.isAfter(nowTz)) {
        target = nowTz.add(const Duration(minutes: 1));
      }

      final scheduleMode = await _resolveAndroidScheduleMode();
      if (kDebugMode) {
        debugPrint(
            '[NotificationService] scheduleNotification scheduleMode=$scheduleMode');
      }
      await _notifications.zonedSchedule(
        id,
        title,
        body,
        target,
        NotificationDetails(android: androidDetails, iOS: iosDetails),
        androidScheduleMode: scheduleMode,
        payload: payload,
      );
    } catch (e) {
      debugPrint('알림 예약 중 오류 발생: $e');
    }
  }

  // 알림 취소
  static Future<void> cancelNotification(int id) async {
    await _notifications.cancel(id);
  }

  // 모든 알림 취소
  static Future<void> cancelAllNotifications() async {
    try {
      // 웹 플랫폼이거나 초기화되지 않은 경우 건너뛰기
      if (_isWeb || !_initialized) {
        debugPrint('웹 플랫폼이거나 알림 서비스가 초기화되지 않아 취소할 수 없습니다.');
        return;
      }

      await _notifications.cancelAll();
      debugPrint('모든 알림이 취소되었습니다.');
    } catch (e) {
      debugPrint('알림 취소 중 오류 발생: $e');
    }
  }

  static Future<void> scheduleSubscriptionNotification(
      SubscriptionModel subscription) async {
    // 웹 플랫폼이거나 초기화되지 않은 경우 건너뛰기
    if (_isWeb || !_initialized) {
      debugPrint('알림 서비스가 초기화되지 않아 알림을 예약할 수 없습니다.');
      return;
    }

    try {
      final notificationId = subscription.id.hashCode;

      final ctx = navigatorKey.currentContext;
      final title = ctx != null
          ? AppLocalizations.of(ctx).expirationReminder
          : 'Expiration Reminder';

      final notificationDetails = NotificationDetails(
        android: AndroidNotificationDetails(
          _paymentChannelId,
          title,
          channelDescription: title,
          importance: Importance.high,
          priority: Priority.high,
          autoCancel: false,
        ),
        iOS: const DarwinNotificationDetails(
          presentAlert: true,
          presentBadge: true,
          presentSound: true,
        ),
      );

      // tz.local 초기화 확인 및 재시도
      tz.Location location;
      try {
        location = tz.local;
      } catch (e) {
        // tz.local이 초기화되지 않은 경우 재시도
        debugPrint('tz.local 초기화되지 않음, 재시도 중...');
        try {
          tz.setLocalLocation(tz.getLocation('Asia/Seoul'));
          location = tz.local;
        } catch (_) {
          // 그래도 실패하면 UTC 사용
          debugPrint('타임존 설정 실패, UTC 사용');
          tz.setLocalLocation(tz.UTC);
          location = tz.UTC;
        }
      }

      final nowTz = tz.TZDateTime.now(location);
      var fireAt = tz.TZDateTime.from(subscription.nextBillingDate, location);
      if (kDebugMode) {
        debugPrint('[NotificationService] scheduleSubscriptionNotification'
            ' id=${subscription.id.hashCode} tz=${location.name}'
            ' now=$nowTz target=$fireAt service=${subscription.serviceName}');
      }
      if (!fireAt.isAfter(nowTz)) {
        // 이미 지난 시각이면 예약 생략
        if (kDebugMode) {
          debugPrint(
              '[NotificationService] skip scheduleSubscriptionNotification (past)');
        }
        return;
      }

      final scheduleMode = await _resolveAndroidScheduleMode();
      if (kDebugMode) {
        debugPrint(
            '[NotificationService] scheduleSubscriptionNotification scheduleMode=$scheduleMode');
      }

      await _notifications.zonedSchedule(
        notificationId,
        title,
        _buildExpirationBody(subscription),
        fireAt,
        notificationDetails,
        androidScheduleMode: scheduleMode,
      );
    } catch (e) {
      debugPrint('구독 알림 예약 중 오류 발생: $e');
    }
  }

  static Future<void> updateSubscriptionNotification(
      SubscriptionModel subscription) async {
    await cancelSubscriptionNotification(subscription);
    await scheduleSubscriptionNotification(subscription);
  }

  static Future<void> cancelSubscriptionNotification(
      SubscriptionModel subscription) async {
    final notificationId = subscription.id.hashCode;
    await _notifications.cancel(notificationId);
  }

  static Future<void> schedulePaymentNotification(
      SubscriptionModel subscription) async {
    if (_isWeb || !_initialized) return;
    final reminderDays = await getReminderDays();
    final hour = await getReminderHour();
    final minute = await getReminderMinute();
    final daily = await isDailyReminderEnabled();
    await schedulePaymentReminder(
      subscription: subscription,
      reminderDays: reminderDays,
      reminderHour: hour,
      reminderMinute: minute,
      isDailyReminder: daily,
    );
  }

  static Future<void> scheduleExpirationNotification(
      SubscriptionModel subscription) async {
    // 웹 플랫폼이거나 초기화되지 않은 경우 건너뛰기
    if (_isWeb || !_initialized) {
      debugPrint('알림 서비스가 초기화되지 않아 알림을 예약할 수 없습니다.');
      return;
    }

    try {
      final expirationDate = subscription.nextBillingDate;
      final reminderDate = expirationDate.subtract(const Duration(days: 7));
      final ctx = navigatorKey.currentContext;
      final loc = ctx != null ? AppLocalizations.of(ctx) : null;

      // tz.local 초기화 확인 및 재시도
      tz.Location location;
      try {
        location = tz.local;
      } catch (e) {
        // tz.local이 초기화되지 않은 경우 재시도
        debugPrint('tz.local 초기화되지 않음, 재시도 중...');
        try {
          tz.setLocalLocation(tz.getLocation('Asia/Seoul'));
          location = tz.local;
        } catch (_) {
          // 그래도 실패하면 UTC 사용
          debugPrint('타임존 설정 실패, UTC 사용');
          tz.setLocalLocation(tz.UTC);
          location = tz.UTC;
        }
      }

      await _notifications.zonedSchedule(
        ('${subscription.id}_expiration').hashCode,
        loc?.expirationReminder ?? _paymentReminderTitle(_getLocaleCode()),
        loc?.expirationReminderBody(subscription.serviceName, 7) ??
            '${subscription.serviceName} subscription expires in 7 days.',
        tz.TZDateTime.from(reminderDate, location),
        const NotificationDetails(
          android: AndroidNotificationDetails(
            _expirationChannelId,
            'Expiration Notifications',
            channelDescription: 'Channel for subscription expiration reminders',
            importance: Importance.high,
            priority: Priority.high,
            autoCancel: false,
          ),
          iOS: DarwinNotificationDetails(
            presentAlert: true,
            presentBadge: true,
            presentSound: true,
          ),
        ),
        androidScheduleMode: await _resolveAndroidScheduleMode(),
      );
    } catch (e) {
      debugPrint('만료 알림 예약 중 오류 발생: $e');
    }
  }

  static Future<void> schedulePaymentReminder({
    required SubscriptionModel subscription,
    int reminderDays = 3,
    int reminderHour = 10,
    int reminderMinute = 0,
    bool isDailyReminder = false,
  }) async {
    // 웹 플랫폼이거나 초기화되지 않은 경우 건너뛰기
    if (_isWeb || !_initialized) {
      debugPrint('웹 플랫폼이거나 알림 서비스가 초기화되지 않아 알림을 예약할 수 없습니다.');
      return;
    }

    try {
      final locale = _getLocaleCode();
      final title = _paymentReminderTitle(locale);

      // tz.local 초기화 확인 및 재시도
      tz.Location location;
      try {
        location = tz.local;
      } catch (e) {
        // tz.local이 초기화되지 않은 경우 재시도
        debugPrint('tz.local 초기화되지 않음, 재시도 중...');
        try {
          tz.setLocalLocation(tz.getLocation('Asia/Seoul'));
          location = tz.local;
        } catch (_) {
          // 그래도 실패하면 UTC 사용
          debugPrint('타임존 설정 실패, UTC 사용');
          tz.setLocalLocation(tz.UTC);
          location = tz.UTC;
        }
      }

      // 기본 알림 예약 (지정된 일수 전)
      final baseLocal = subscription.nextBillingDate
          .subtract(Duration(days: reminderDays))
          .copyWith(
            hour: reminderHour,
            minute: reminderMinute,
            second: 0,
            millisecond: 0,
            microsecond: 0,
          );
      final nowTz = tz.TZDateTime.now(location);
      var scheduledDate = tz.TZDateTime.from(baseLocal, location);
      if (kDebugMode) {
        debugPrint('[NotificationService] schedulePaymentReminder(base)'
            ' id=${subscription.id.hashCode} tz=${location.name}'
            ' now=$nowTz requested=$baseLocal scheduled=$scheduledDate'
            ' days=$reminderDays time=${reminderHour.toString().padLeft(2, '0')}:${reminderMinute.toString().padLeft(2, '0')}'
            ' service=${subscription.serviceName}');
      }
      if (!scheduledDate.isAfter(nowTz)) {
        // 지정일이 과거면 최소 1분 뒤로
        scheduledDate = nowTz.add(const Duration(minutes: 1));
        if (kDebugMode) {
          debugPrint(
              '[NotificationService] schedulePaymentReminder(base) adjusted to $scheduledDate');
        }
      }

      // 남은 일수에 따른 메시지 생성
      final daysText = _daysInText(locale, reminderDays);

      // 이벤트 종료로 인한 가격 변동 확인
      final body = await _buildPaymentBody(subscription, daysText);

      final scheduleMode = await _resolveAndroidScheduleMode();
      if (kDebugMode) {
        debugPrint(
            '[NotificationService] schedulePaymentReminder(base) scheduleMode=$scheduleMode');
      }

      await _notifications.zonedSchedule(
        subscription.id.hashCode,
        title,
        body,
        scheduledDate,
        NotificationDetails(
          android: AndroidNotificationDetails(
            _paymentChannelId,
            title,
            channelDescription: title,
            importance: Importance.high,
            priority: Priority.high,
            autoCancel: false,
          ),
          iOS: const DarwinNotificationDetails(
            presentAlert: true,
            presentBadge: true,
            presentSound: true,
          ),
        ),
        androidScheduleMode: scheduleMode,
        payload: _paymentPayload(subscription.id),
      );

      // 매일 반복 알림 설정 (2일 이상 전에 알림 시작 & 반복 알림 활성화된 경우)
      if (isDailyReminder && reminderDays >= 2) {
        // 첫 번째 알림 다음 날부터 결제일 전날까지 매일 알림 예약
        for (int i = reminderDays - 1; i >= 1; i--) {
          final dailyLocal =
              subscription.nextBillingDate.subtract(Duration(days: i)).copyWith(
                    hour: reminderHour,
                    minute: reminderMinute,
                    second: 0,
                    millisecond: 0,
                    microsecond: 0,
                  );
          final dailyDate = tz.TZDateTime.from(dailyLocal, location);
          if (kDebugMode) {
            debugPrint('[NotificationService] schedulePaymentReminder(daily)'
                ' id=${subscription.id.hashCode + i} tz=${location.name}'
                ' now=$nowTz requested=$dailyLocal scheduled=$dailyDate'
                ' daysLeft=$i');
          }
          if (!dailyDate.isAfter(nowTz)) {
            // 과거면 건너뜀
            if (kDebugMode) {
              debugPrint('[NotificationService] skip daily (past)');
            }
            continue;
          }

          // 남은 일수에 따른 메시지 생성
          final remainingDaysText = _daysInText(locale, i);

          // 각 날짜에 대한 이벤트 종료 확인
          final dailyNotificationBody =
              await _buildPaymentBody(subscription, remainingDaysText);

          await _notifications.zonedSchedule(
            subscription.id.hashCode + i, // 고유한 ID 생성을 위해 날짜 차이 더함
            title,
            dailyNotificationBody,
            dailyDate,
            NotificationDetails(
              android: AndroidNotificationDetails(
                _paymentChannelId,
                title,
                channelDescription: title,
                importance: Importance.high,
                priority: Priority.high,
                autoCancel: false,
              ),
              iOS: const DarwinNotificationDetails(
                presentAlert: true,
                presentBadge: true,
                presentSound: true,
              ),
            ),
            androidScheduleMode: scheduleMode,
            payload: _paymentPayload(subscription.id),
          );
        }
      }
    } catch (e) {
      debugPrint('결제 알림 예약 중 오류 발생: $e');
    }
  }

  // 디버그 테스트용: 즉시 결제 알림을 보여줍니다.
  static Future<void> showTestPaymentNotification() async {
    if (_isWeb || !_initialized) return;
    try {
      final locale = _getLocaleCode();
      final ctx = navigatorKey.currentContext;
      final loc = ctx != null ? AppLocalizations.of(ctx) : null;
      final title = loc?.paymentReminder ?? _paymentReminderTitle(locale);
      final amountText =
          await CurrencyUtil.formatAmountWithLocale(10000.0, 'KRW', locale);

      final body = loc?.testSubscriptionBody(amountText) ??
          'Test subscription • $amountText';

      await _notifications.show(
        DateTime.now().millisecondsSinceEpoch.remainder(1 << 31),
        title,
        body,
        NotificationDetails(
          android: AndroidNotificationDetails(
            'subscription_channel',
            title,
            channelDescription: title,
            importance: Importance.high,
            priority: Priority.high,
          ),
          iOS: const DarwinNotificationDetails(
            presentAlert: true,
            presentBadge: true,
            presentSound: true,
          ),
        ),
      );
    } catch (e) {
      debugPrint('테스트 결제 알림 표시 실패: $e');
    }
  }

  static String getNotificationBody(String serviceName, double amount) {
    final ctx = navigatorKey.currentContext;
    final loc = ctx != null ? AppLocalizations.of(ctx) : null;
    final amountText = amount.toStringAsFixed(0);
    return loc?.paymentChargeNotification(serviceName, amountText) ??
        '$serviceName subscription charge $amountText was completed.';
  }

  static Future<String> _buildPaymentBody(
      SubscriptionModel subscription, String daysText) async {
    final ctx = navigatorKey.currentContext;
    final locale =
        ctx != null ? AppLocalizations.of(ctx).locale.languageCode : 'en';
    final warnText = ctx != null
        ? AppLocalizations.of(ctx).eventDiscountEndsBeforeBilling
        : 'Event discount ends before billing date';
    final amountText = await CurrencyUtil.formatAmountWithLocale(
        subscription.currentPrice, subscription.currency, locale);
    if (subscription.isEventActive &&
        subscription.eventEndDate != null &&
        subscription.eventEndDate!.isBefore(subscription.nextBillingDate) &&
        subscription.eventEndDate!.isAfter(DateTime.now())) {
      return '${subscription.serviceName} • $amountText • $daysText\n⚠️ $warnText';
    }
    // 일반 알림
    if (ctx != null) {
      return '${subscription.serviceName} • $amountText • $daysText';
    }
    return '${subscription.serviceName} • $amountText • $daysText';
  }

  static String _buildExpirationBody(SubscriptionModel subscription) {
    final ctx = navigatorKey.currentContext;
    if (ctx != null) {
      final date =
          AppLocalizations.of(ctx).formatDate(subscription.nextBillingDate);
      return '${subscription.serviceName} • $date';
    }
    return '${subscription.serviceName} • ${subscription.nextBillingDate.toLocal()}';
  }

  static String _getLocaleCode() {
    final ctx = navigatorKey.currentContext;
    if (ctx != null) {
      return AppLocalizations.of(ctx).locale.languageCode;
    }
    return 'en';
  }

  static String _paymentReminderTitle(String locale) {
    final ctx = navigatorKey.currentContext;
    if (ctx != null) {
      return AppLocalizations.of(ctx).paymentReminder;
    }
    switch (locale) {
      case 'ko':
        return '결제 예정 알림';
      case 'ja':
        return '支払い予定の通知';
      case 'zh':
        return '付款提醒';
      default:
        return 'Payment Reminder';
    }
  }

  static String _daysInText(String locale, int days) {
    switch (locale) {
      case 'ko':
        return '$days일 후';
      case 'ja':
        return '$days日後';
      case 'zh':
        return '$days天后';
      default:
        return 'in $days day(s)';
    }
  }
}
