import 'package:flutter_test/flutter_test.dart';
import 'package:timezone/timezone.dart' as tz;
import 'package:timezone/data/latest.dart' as tz_data;
import 'package:integration_test/integration_test.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:lanebow/models/event_model.dart';
import 'package:lanebow/services/notification_service.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'notification_integration_test.mocks.dart';

@GenerateMocks([
  FlutterLocalNotificationsPlugin,
  AndroidFlutterLocalNotificationsPlugin,
  IOSFlutterLocalNotificationsPlugin,
])

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();
  
  // timezone 초기화
  tz_data.initializeTimeZones();
  
  late MockFlutterLocalNotificationsPlugin mockNotificationsPlugin;
  late MockAndroidFlutterLocalNotificationsPlugin mockAndroidPlugin;
  late MockIOSFlutterLocalNotificationsPlugin mockIOSPlugin;
  late NotificationService originalNotificationService;

  setUp(() {
    // 목 플러그인 생성
    mockNotificationsPlugin = MockFlutterLocalNotificationsPlugin();
    mockAndroidPlugin = MockAndroidFlutterLocalNotificationsPlugin();
    mockIOSPlugin = MockIOSFlutterLocalNotificationsPlugin();
    
    // 원래 인스턴스 저장
    originalNotificationService = NotificationService();
    
    // 목 플러그인 설정
    when(mockNotificationsPlugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>())
        .thenReturn(mockAndroidPlugin);
    when(mockNotificationsPlugin.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>())
        .thenReturn(mockIOSPlugin);
    
    // 권한 요청 목업
    when(mockIOSPlugin.requestPermissions(
      alert: true,
      badge: true,
      sound: true,
      critical: false,
      provisional: false,
    )).thenAnswer((_) async => true);
    
    // 알림 예약 목업 - 모든 matcher 제거하고 실제 값만 사용
    when(mockNotificationsPlugin.zonedSchedule(
      0, // 알림 ID
      '알림 제목',
      '알림 내용',
      tz.TZDateTime.now(tz.local).add(const Duration(hours: 1)),
      const NotificationDetails(
        android: AndroidNotificationDetails(
          'event_reminder_channel',
          '이벤트 리마인더',
          channelDescription: '예정된 이벤트에 대한 알림을 표시합니다',
          importance: Importance.high,
          priority: Priority.high,
        ),
        iOS: DarwinNotificationDetails(
          presentAlert: true,
          presentBadge: true,
          presentSound: true,
        ),
      ),
      androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
      matchDateTimeComponents: DateTimeComponents.time,
      payload: 'test-payload',
    )).thenAnswer((_) async {});
    
    // 테스트용 NotificationService 생성 및 설정
    // 새로 추가한 createTestInstance 메서드를 사용하여 mock 플러그인을 주입
    final testNotificationService = NotificationService.createTestInstance(mockNotificationsPlugin);
    NotificationService.setTestInstance(testNotificationService);
  });

  tearDown(() {
    // 테스트 후 원래 NotificationService 복원
    NotificationService.setTestInstance(originalNotificationService);
  });

  group('알림 서비스 통합 테스트', () {
    test('알림 권한 요청 기능이 작동해야 함', () async {
      // NotificationService 테스트 인스턴스 생성 및 설정
      final notificationService = NotificationService();
      NotificationService.setTestInstance(notificationService);
      
      // given
      when(mockNotificationsPlugin.initialize(any, onDidReceiveNotificationResponse: anyNamed('onDidReceiveNotificationResponse')))
          .thenAnswer((_) async => true);
          
      when(mockIOSPlugin.requestPermissions(
        alert: true,
        badge: true,
        sound: true,
        critical: false,
        provisional: false,
      )).thenAnswer((_) async => true);

      // when - 위젯 테스트 대신 직접 메서드 호출
      await notificationService.requestPermission();

      // then - 권한 요청 메서드가 호출되었는지 확인
      verify(mockIOSPlugin.requestPermissions(
        alert: true,
        badge: true,
        sound: true,
        critical: false,
        provisional: false,
      )).called(1);
    });

    test('이벤트 알림 설정 기능이 작동해야 함', () async {
      // given
      when(mockNotificationsPlugin.initialize(any, onDidReceiveNotificationResponse: anyNamed('onDidReceiveNotificationResponse')))
          .thenAnswer((_) async => true);
          
      // 테스트용 이벤트 생성
      final testEvent = Event(
        id: 'test_event_id',
        clubId: 'test_club_id',
        title: '테스트 이벤트',
        description: '테스트 이벤트 설명',
        startDate: DateTime.now().add(const Duration(hours: 2)),
        endDate: DateTime.now().add(const Duration(hours: 4)),
        location: '테스트 장소',
        maxParticipants: 10,
        gameCount: 3,
        participantFee: 10000,
        registrationDeadline: DateTime.now().add(const Duration(days: 2)),
        isActive: true,
        createdBy: 'test_user_id',
        type: '팀전',
      );

      // NotificationService 테스트 인스턴스 생성 및 설정
      final notificationService = NotificationService();
      NotificationService.setTestInstance(notificationService);
      
      // zonedSchedule 메서드 stub 설정 - any matcher 사용
      when(mockNotificationsPlugin.zonedSchedule(
        any,
        any,
        any,
        any,
        any,
        androidScheduleMode: anyNamed('androidScheduleMode'),
        matchDateTimeComponents: anyNamed('matchDateTimeComponents'),
        payload: anyNamed('payload'),
      )).thenAnswer((_) async {});
      
      // when - 알림 설정 메서드 직접 호출
      await notificationService.scheduleEventStartReminder(testEvent);
      
      // then - zonedSchedule이 호출되었는지 확인
      verify(mockNotificationsPlugin.zonedSchedule(
        any,
        '이벤트 시작 알림',
        '${testEvent.title} 이벤트가 1시간 후에 시작됩니다.',
        any,
        any,
        androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
        matchDateTimeComponents: DateTimeComponents.time,
        payload: testEvent.id,
      )).called(1);
    });
  });
}

// 테스트를 위한 NotificationService 확장 클래스
class TestNotificationService implements NotificationService {
  final FlutterLocalNotificationsPlugin mockNotificationsPlugin;
  bool _isInitialized = false;

  TestNotificationService(this.mockNotificationsPlugin);

  @override
  bool get isInitialized => _isInitialized;
  
  @override
  set isInitialized(bool value) {
    _isInitialized = value;
  }
  
  @override
  Future<void> initialize() async {
    _isInitialized = true;
    return Future.value();
  }
  
  @override
  Future<bool> requestPermission() async {
    return Future.value(true);
  }
  
  @override
  Future<void> showNotification({required int id, required String title, required String body, String? payload}) {
    return Future.value();
  }
  
  @override
  Future<void> scheduleNotification({required int id, required String title, required String body, required DateTime scheduledDate, String? payload}) {
    return Future.value();
  }
  
  @override
  Future<void> scheduleEventStartReminder(Event event) {
    return Future.value();
  }
  
  @override
  Future<void> scheduleRegistrationDeadlineReminder(Event event) {
    return Future.value();
  }
  
  @override
  Future<void> cancelEventNotifications(String eventId) {
    return Future.value();
  }
  
  @override
  Future<void> cancelAllNotifications() {
    return Future.value();
  }
}

// NotificationService에 테스트 인스턴스를 설정하기 위한 확장
extension NotificationServiceTestExtension on NotificationService {
  static void setTestInstance(NotificationService instance) {
    // 이 메서드는 실제 구현에서는 작동하지 않지만, 테스트 목적으로 추가
    // 실제로는 NotificationService 클래스에 이 기능을 추가해야 함
    // 테스트에서는 이 메서드가 호출될 때 NotificationService._instance를 교체하는 방식으로 동작해야 함
  }
}

// MockIOSFlutterLocalNotificationsPlugin은 이제 @GenerateMocks에 의해 자동 생성됩니다.
