import 'dart:math';
import 'package:flutter/foundation.dart';
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 '../utils/app_logger.dart';

/// 알림 서비스 싱글톤 클래스
class NotificationService {
  // 싱글톤 인스턴스
  static final NotificationService _instance = NotificationService._internal();
  factory NotificationService() => _instance;
  NotificationService._internal();

  // Flutter Local Notifications 플러그인
  final FlutterLocalNotificationsPlugin _notifications =
      FlutterLocalNotificationsPlugin();
  bool _initialized = false;

  // 알림 채널 정보
  static const String _channelId = 'lunchpick_visit_reminder';
  static const String _channelName = '방문 확인 알림';
  static const String _channelDescription = '점심 식사 후 방문을 확인하는 알림입니다.';

  // 알림 ID (방문 확인용)
  static const int _visitReminderNotificationId = 1;
  bool _timezoneReady = false;
  tz.Location? _cachedLocation;

  /// 초기화 여부
  bool get isInitialized => _initialized;

  /// 초기화 및 권한 요청 보장
  Future<bool> ensureInitialized({bool requestPermission = false}) async {
    if (!_initialized) {
      _initialized = await initialize();
    }

    if (!_initialized) return false;

    if (requestPermission) {
      final alreadyGranted = await checkPermission();
      if (alreadyGranted) return true;
      return await this.requestPermission();
    }

    return true;
  }

  /// 알림 서비스 초기화
  Future<bool> initialize() async {
    if (_initialized) return true;
    if (kIsWeb) return false;

    // 시간대 초기화
    await _ensureLocalTimezone();

    // Android 초기화 설정
    const androidInitSettings = AndroidInitializationSettings(
      '@mipmap/ic_launcher',
    );

    // iOS 초기화 설정
    final iosInitSettings = DarwinInitializationSettings(
      requestAlertPermission: true,
      requestBadgePermission: true,
      requestSoundPermission: true,
      onDidReceiveLocalNotification: (id, title, body, payload) async {
        // iOS 9 이하 버전 대응
      },
    );

    // macOS 초기화 설정
    final macOSInitSettings = DarwinInitializationSettings(
      requestAlertPermission: true,
      requestBadgePermission: true,
      requestSoundPermission: true,
    );

    // 플랫폼별 초기화 설정 통합
    final initSettings = InitializationSettings(
      android: androidInitSettings,
      iOS: iosInitSettings,
      macOS: macOSInitSettings,
    );

    // 알림 플러그인 초기화
    try {
      final initialized = await _notifications.initialize(
        initSettings,
        onDidReceiveNotificationResponse: _onNotificationTap,
        onDidReceiveBackgroundNotificationResponse:
            _onBackgroundNotificationTap,
      );
      _initialized = initialized ?? false;
    } catch (e) {
      _initialized = false;
      AppLogger.debug('알림 초기화 실패: $e');
    }

    // Android 알림 채널 생성 (웹이 아닌 경우에만)
    if (_initialized && defaultTargetPlatform == TargetPlatform.android) {
      await _createNotificationChannel();
    }

    return _initialized;
  }

  /// Android 알림 채널 생성
  Future<void> _createNotificationChannel() async {
    const androidChannel = AndroidNotificationChannel(
      _channelId,
      _channelName,
      description: _channelDescription,
      importance: Importance.high,
      playSound: true,
      enableVibration: true,
    );

    try {
      await _notifications
          .resolvePlatformSpecificImplementation<
            AndroidFlutterLocalNotificationsPlugin
          >()
          ?.createNotificationChannel(androidChannel);
    } catch (e) {
      AppLogger.debug('안드로이드 채널 생성 실패: $e');
    }
  }

  /// 알림 권한 요청
  Future<bool> requestPermission() async {
    if (kIsWeb) return false;

    if (defaultTargetPlatform == TargetPlatform.android) {
      final androidImplementation = _notifications
          .resolvePlatformSpecificImplementation<
            AndroidFlutterLocalNotificationsPlugin
          >();

      if (androidImplementation != null) {
        final granted = await androidImplementation
            .requestNotificationsPermission();
        return granted ?? false;
      }
    } else if (defaultTargetPlatform == TargetPlatform.iOS ||
        defaultTargetPlatform == TargetPlatform.macOS) {
      final iosImplementation = _notifications
          .resolvePlatformSpecificImplementation<
            IOSFlutterLocalNotificationsPlugin
          >();
      final macosImplementation = _notifications
          .resolvePlatformSpecificImplementation<
            MacOSFlutterLocalNotificationsPlugin
          >();

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

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

    return false;
  }

  /// 권한 상태 확인
  Future<bool> checkPermission() async {
    if (kIsWeb) return false;

    if (defaultTargetPlatform == TargetPlatform.android) {
      final androidImplementation = _notifications
          .resolvePlatformSpecificImplementation<
            AndroidFlutterLocalNotificationsPlugin
          >();

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

    if (defaultTargetPlatform == TargetPlatform.iOS ||
        defaultTargetPlatform == TargetPlatform.macOS) {
      final iosImplementation = _notifications
          .resolvePlatformSpecificImplementation<
            IOSFlutterLocalNotificationsPlugin
          >();
      final macosImplementation = _notifications
          .resolvePlatformSpecificImplementation<
            MacOSFlutterLocalNotificationsPlugin
          >();

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

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

    // iOS/macOS 외 플랫폼은 기본적으로 허용으로 간주
    return true;
  }

  /// 정확 알람 권한 가능 여부 확인 (Android 12+)
  Future<bool> canScheduleExactAlarms() async {
    if (kIsWeb || defaultTargetPlatform != TargetPlatform.android) {
      return true;
    }

    try {
      final androidImplementation = _notifications
          .resolvePlatformSpecificImplementation<
            AndroidFlutterLocalNotificationsPlugin
          >();
      final canExact = await androidImplementation
          ?.canScheduleExactNotifications();
      return canExact ?? true;
    } catch (e) {
      AppLogger.debug('정확 알람 권한 확인 실패: $e');
      return false;
    }
  }

  /// 정확 알람 권한 요청 (Android 12+ 설정 화면 이동)
  Future<bool> requestExactAlarmsPermission() async {
    if (kIsWeb || defaultTargetPlatform != TargetPlatform.android) {
      return true;
    }

    try {
      final androidImplementation = _notifications
          .resolvePlatformSpecificImplementation<
            AndroidFlutterLocalNotificationsPlugin
          >();
      final granted = await androidImplementation
          ?.requestExactAlarmsPermission();
      return granted ?? false;
    } catch (e) {
      AppLogger.debug('정확 알람 권한 요청 실패: $e');
      return false;
    }
  }

  // 알림 탭 콜백
  static void Function(NotificationResponse)? onNotificationTap;

  /// 방문 확인 알림 예약
  Future<void> scheduleVisitReminder({
    required String restaurantId,
    required String restaurantName,
    required DateTime recommendationTime,
    int? delayMinutes,
  }) async {
    try {
      final ready = await ensureInitialized();
      if (!ready) {
        AppLogger.debug('알림 서비스가 초기화되지 않아 예약을 건너뜁니다.');
        return;
      }

      final permissionGranted = await checkPermission();
      if (!permissionGranted) {
        AppLogger.debug('알림 권한이 없어 예약을 건너뜁니다.');
        return;
      }

      final location = await _ensureLocalTimezone();
      final minutesToWait = max(delayMinutes ?? 90 + Random().nextInt(31), 1);
      final scheduledTime = tz.TZDateTime.now(
        location,
      ).add(Duration(minutes: minutesToWait));

      // 알림 상세 설정
      final androidDetails = AndroidNotificationDetails(
        _channelId,
        _channelName,
        channelDescription: _channelDescription,
        importance: Importance.high,
        priority: Priority.high,
        ticker: '방문 확인',
        icon: '@mipmap/ic_launcher',
        autoCancel: true,
        enableVibration: true,
        playSound: true,
      );

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

      final notificationDetails = NotificationDetails(
        android: androidDetails,
        iOS: iosDetails,
        macOS: iosDetails,
      );

      // 알림 예약
      await _notifications.zonedSchedule(
        _visitReminderNotificationId,
        '다녀왔음? 🍴',
        '$restaurantName 어땠어요? 방문 기록을 남겨주세요!',
        scheduledTime,
        notificationDetails,
        androidScheduleMode: await _resolveAndroidScheduleMode(),
        uiLocalNotificationDateInterpretation:
            UILocalNotificationDateInterpretation.absoluteTime,
        payload:
            'visit_reminder|$restaurantId|$restaurantName|${recommendationTime.toIso8601String()}',
      );
      AppLogger.debug('알림 예약됨: ${scheduledTime.toLocal()} ($minutesToWait분 후)');
    } catch (e) {
      AppLogger.debug('알림 예약 실패: $e');
    }
  }

  /// 예약된 방문 확인 알림 취소
  Future<void> cancelVisitReminder() async {
    if (!await ensureInitialized()) return;
    await _notifications.cancel(_visitReminderNotificationId);
  }

  /// 모든 알림 취소
  Future<void> cancelAllNotifications() async {
    if (!await ensureInitialized()) return;
    await _notifications.cancelAll();
  }

  /// 예약된 알림 목록 조회
  Future<List<PendingNotificationRequest>> getPendingNotifications() async {
    if (!await ensureInitialized()) return [];
    return await _notifications.pendingNotificationRequests();
  }

  /// 방문 확인 알림이 예약되어 있는지 확인
  Future<bool> hasVisitReminderScheduled() async {
    if (!await ensureInitialized()) return false;
    final pending = await getPendingNotifications();
    return pending.any((item) => item.id == _visitReminderNotificationId);
  }

  /// 타임존을 안전하게 초기화하고 tz.local을 반환
  Future<tz.Location> _ensureLocalTimezone() async {
    if (_cachedLocation != null) return _cachedLocation!;
    if (!_timezoneReady) {
      try {
        tz.initializeTimeZones();
      } catch (_) {
        // 초기화 실패 시에도 계속 진행
      }
      _timezoneReady = true;
    }

    try {
      tz.setLocalLocation(tz.getLocation('Asia/Seoul'));
      _cachedLocation = tz.local;
    } catch (_) {
      // 로컬 타임존을 가져오지 못하면 UTC로 강제 설정
      tz.setLocalLocation(tz.UTC);
      _cachedLocation = tz.UTC;
    }
    return _cachedLocation!;
  }

  /// 정확 알람 권한 여부에 따라 스케줄 모드 결정
  Future<AndroidScheduleMode> _resolveAndroidScheduleMode() async {
    if (kIsWeb || defaultTargetPlatform != TargetPlatform.android) {
      return AndroidScheduleMode.exactAllowWhileIdle;
    }

    final canExact = await canScheduleExactAlarms();
    if (!canExact) {
      AppLogger.debug('정확 알람 권한 없음 → 근사 모드로 예약');
      return AndroidScheduleMode.inexactAllowWhileIdle;
    }

    return AndroidScheduleMode.exactAllowWhileIdle;
  }

  /// 알림 탭 이벤트 처리
  void _onNotificationTap(NotificationResponse response) {
    if (onNotificationTap != null) {
      onNotificationTap!(response);
    } else if (response.payload != null) {
      AppLogger.debug('알림 탭: ${response.payload}');
    }
  }

  /// 백그라운드 알림 탭 이벤트 처리
  @pragma('vm:entry-point')
  static void _onBackgroundNotificationTap(NotificationResponse response) {
    if (onNotificationTap != null) {
      onNotificationTap!(response);
    } else if (response.payload != null) {
      AppLogger.debug('백그라운드 알림 탭: ${response.payload}');
    }
  }

  /// 즉시 알림 표시 (테스트용)
  Future<void> showImmediateNotification({
    required String title,
    required String body,
  }) async {
    const androidDetails = AndroidNotificationDetails(
      _channelId,
      _channelName,
      channelDescription: _channelDescription,
      importance: Importance.high,
      priority: Priority.high,
    );

    const iosDetails = DarwinNotificationDetails();

    const notificationDetails = NotificationDetails(
      android: androidDetails,
      iOS: iosDetails,
      macOS: iosDetails,
    );

    await _notifications.show(0, title, body, notificationDetails);
  }
}
