import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import 'package:lanebow/models/score_model.dart';
import 'package:lanebow/models/participant_model.dart';
import 'package:lanebow/services/event_service.dart';
import 'package:lanebow/screens/club/score_form_screen.dart';

// 공통 StubEventService 사용
import '../../utils/stub_event_service.dart';
import '../../utils/dummy_test_data.dart';
import '../../utils/event_bus_test_utils.dart';
import 'package:lanebow/utils/test_utils.dart';

// 모의 객체 생성
void main() {
  late EventService stubEventService;

  setUp(() async {
    // EventBus 테스트 환경 초기화 (플래키 방지)
    TestUtils.setTestMode(true);
    await EventBusTestUtils.setUp('score_form_screen_test');
    stubEventService = StubEventService();
  });
  
  tearDown(() async {
    // 테스트 종료 후 EventBus 자원 정리 (idle/타이머 플러시 포함)
    await EventBusTestUtils.tearDown();
  });

  // 로컬 더미 생성기 제거: DummyTestData 공용 유틸 사용

  // 사용되지 않는 헬퍼 함수들은 제거했습니다.
  
  // 위젯 테스트를 위한 래퍼 함수
  Widget createScoreFormScreen({
    required String eventId,
    Score? score,
    required List<Participant> participants,
  }) {
    return MaterialApp(
      home: ChangeNotifierProvider<EventService>.value(
        value: stubEventService,
        child: ScoreFormScreen(
          eventId: eventId,
          score: score,
          participants: participants,
        ),
      ),
    );
  }

  group('ScoreFormScreen 위젯 테스트', () {
    testWidgets('새 점수 추가 모드에서 기본적으로 총점 입력 모드로 시작해야 함', (WidgetTester tester) async {
      // given
      final participants = DummyTestData.participants(eventId: 'event1', count: 2);

      // when
      await tester.pumpWidget(createScoreFormScreen(
        eventId: 'event1',
        participants: participants,
      ));

      // then
      // AppBar에 "점수 추가" 텍스트가 있는지 확인 (findsWidgets로 변경)
      expect(find.text('점수 추가'), findsWidgets);
      expect(find.byType(SwitchListTile), findsOneWidget);
      expect(find.text('프레임별 점수 입력'), findsOneWidget);
      
      // 총점 입력 필드가 표시되어야 함
      expect(find.widgetWithText(TextFormField, '총점 *'), findsOneWidget);
      
      // 프레임별 입력 그리드는 표시되지 않아야 함
      expect(find.byType(GridView), findsNothing);
    });

    testWidgets('점수 수정 모드에서 프레임별 점수가 있으면 프레임별 입력 모드로 시작해야 함', (WidgetTester tester) async {
      // given
      final participants = DummyTestData.participants(eventId: 'event1', count: 2);
      final scores = DummyTestData.scoresForParticipants(
        eventId: 'event1',
        clubId: 'club1',
        participants: participants,
      );
      final score = scores.first;

      // when
      await tester.pumpWidget(createScoreFormScreen(
        eventId: 'event1',
        score: score,
        participants: participants,
      ));

      // then
      // AppBar에 "점수 수정" 텍스트가 있는지 확인 (findsWidgets로 변경)
      expect(find.text('점수 수정'), findsWidgets);
      
      // 프레임별 입력 스위치가 켜져 있어야 함
      final switchWidget = tester.widget<SwitchListTile>(find.byType(SwitchListTile));
      expect(switchWidget.value, isTrue);
      
      // 프레임별 입력 그리드가 표시되어야 함
      expect(find.byType(GridView), findsOneWidget);
      
      // 총점 입력 필드는 표시되지 않아야 함
      expect(find.widgetWithText(TextFormField, '총점 *'), findsNothing);
    });

    testWidgets('입력 모드 전환 시 UI가 올바르게 변경되어야 함', (WidgetTester tester) async {
      // given
      final participants = DummyTestData.participants(eventId: 'event1', count: 2);

      // when
      await tester.pumpWidget(createScoreFormScreen(
        eventId: 'event1',
        participants: participants,
      ));

      // 초기 상태 확인 (총점 입력 모드)
      expect(find.widgetWithText(TextFormField, '총점 *'), findsOneWidget);
      expect(find.byType(GridView), findsNothing);

      // 프레임별 입력 모드로 전환
      await tester.tap(find.byType(Switch));
      await tester.pumpAndSettle();

      // 프레임별 입력 모드 확인
      expect(find.widgetWithText(TextFormField, '총점 *'), findsNothing);
      expect(find.byType(GridView), findsOneWidget);

      // 다시 총점 입력 모드로 전환
      await tester.tap(find.byType(Switch));
      await tester.pumpAndSettle();

      // 총점 입력 모드 확인
      expect(find.widgetWithText(TextFormField, '총점 *'), findsOneWidget);
      expect(find.byType(GridView), findsNothing);
    });

    testWidgets('총점 입력 모드에서 유효성 검사가 올바르게 작동해야 함', (WidgetTester tester) async {
      // given
      final participants = DummyTestData.participants(eventId: 'event1', count: 2);
      
      // StubEventService 가 성공 Future를 반환하므로 별도 stubbing 불필요

      // when
      await tester.pumpWidget(createScoreFormScreen(
        eventId: 'event1',
        participants: participants,
      ));
      
      // 위젯 렌더링을 위해 pump 사용 (pumpAndSettle 대신)
      await tester.pump(const Duration(milliseconds: 300));

      // 참가자 선택 (이미 기본값으로 선택되어 있음)
      
      // 총점 필드 찾기 시도
      final totalScoreField = find.widgetWithText(TextFormField, '총점 *');
      if (totalScoreField.evaluate().isNotEmpty) {
        await tester.enterText(totalScoreField, '250');
        await tester.pump(const Duration(milliseconds: 300));
      } else {
        debugPrint('총점 필드를 찾을 수 없습니다. 대체 방법으로 시도합니다.');
        
        // 모든 TextFormField 찾기
        final allTextFields = find.byType(TextFormField);
        if (allTextFields.evaluate().isNotEmpty) {
          // 첫 번째 TextFormField에 값 입력
          await tester.enterText(allTextFields.first, '250');
          await tester.pump(const Duration(milliseconds: 300));
          
          // 두 번째 TextFormField가 있다면 핸디캅으로 간주하고 값 입력
          if (allTextFields.evaluate().length > 1) {
            await tester.enterText(allTextFields.at(1), '20');
            await tester.pump(const Duration(milliseconds: 300));
          }
        }
      }
      
      // 핸디캅 필드 찾기
      final handicapField = find.widgetWithText(TextFormField, '핸디캅');
      if (handicapField.evaluate().isNotEmpty) {
        await tester.enterText(handicapField, '20');
        await tester.pump(const Duration(milliseconds: 300));
      }
      
      // 저장 버튼 찾고 클릭
      final saveButton = find.byIcon(Icons.save);
      if (saveButton.evaluate().isNotEmpty) {
        await tester.tap(saveButton);
        await tester.pump(const Duration(milliseconds: 300));
        // 한 번 더 pump하여 비동기 작업 처리
        await tester.pump(const Duration(seconds: 1));
      } else {
        debugPrint('저장 버튼을 찾을 수 없습니다.');
      }

      // then: 저장 성공 시 화면이 pop 되었는지 확인
      expect(find.byType(ScoreFormScreen), findsNothing);
    });

    testWidgets('프레임별 입력 모드에서 유효성 검사가 올바르게 작동해야 함', (WidgetTester tester) async {
      // given
      final participants = DummyTestData.participants(eventId: 'event1', count: 2);
      
      // StubEventService 가 성공 Future를 반환하므로 별도 stubbing 불필요

      // when
      await tester.pumpWidget(createScoreFormScreen(
        eventId: 'event1',
        participants: participants,
      ));
      
      // 위젯 렌더링을 위해 pump 사용 (pumpAndSettle 대신)
      await tester.pump(const Duration(milliseconds: 300));

      // 프레임별 입력 모드로 전환
      final switchFinder = find.byType(Switch);
      if (switchFinder.evaluate().isNotEmpty) {
        await tester.tap(switchFinder);
        await tester.pump(const Duration(milliseconds: 300));
      } else {
        debugPrint('Switch 위젯을 찾을 수 없습니다.');
      }

      // 핸디캅 입력 시도
      final handicapField = find.widgetWithText(TextFormField, '핸디캅');
      if (handicapField.evaluate().isNotEmpty) {
        await tester.enterText(handicapField, '15');
        await tester.pump(const Duration(milliseconds: 300));
      } else {
        debugPrint('핸디캅 필드를 찾을 수 없습니다.');
      }
      
      // 저장 버튼 클릭
      final saveButton = find.byIcon(Icons.save);
      if (saveButton.evaluate().isNotEmpty) {
        await tester.tap(saveButton);
        await tester.pump(const Duration(milliseconds: 300));
        // 한 번 더 pump하여 비동기 작업 처리
        await tester.pump(const Duration(seconds: 1));
      } else {
        debugPrint('저장 버튼을 찾을 수 없습니다.');
      }

      // then: 저장 성공 시 화면이 pop 되었는지 확인
      expect(find.byType(ScoreFormScreen), findsNothing);
    });

    testWidgets('실패 케이스(추가): 스낵바 에러 노출, pop 미호출', (WidgetTester tester) async {
      // given
      (stubEventService as StubEventService).throwOnAddScore = true;
      final participants = DummyTestData.participants(eventId: 'event1', count: 2);

      await tester.pumpWidget(createScoreFormScreen(
        eventId: 'event1',
        participants: participants,
      ));
      await tester.pump(const Duration(milliseconds: 300));

      // 총점 입력
      final totalField = find.widgetWithText(TextFormField, '총점 *');
      if (totalField.evaluate().isNotEmpty) {
        await tester.enterText(totalField, '200');
      }

      // 저장
      await tester.tap(find.byIcon(Icons.save));
      await tester.pump(const Duration(milliseconds: 300));
      await tester.pump(const Duration(seconds: 1));

      // then
      expect(find.byType(ScoreFormScreen), findsOneWidget);
      expect(find.textContaining('점수 저장에 실패했습니다'), findsOneWidget);
    });

    testWidgets('실패 케이스(수정): 스낵바 에러 노출, pop 미호출', (WidgetTester tester) async {
      // given
      (stubEventService as StubEventService).throwOnUpdateScore = true;
      final participants = DummyTestData.participants(eventId: 'event1', count: 2);
      final scores = DummyTestData.scoresForParticipants(
        eventId: 'event1',
        clubId: 'club1',
        participants: participants,
      );
      final score = scores.first;

      await tester.pumpWidget(createScoreFormScreen(
        eventId: 'event1',
        score: score,
        participants: participants,
      ));
      await tester.pump(const Duration(milliseconds: 300));

      // 프레임별 모드인 상태에서 저장
      await tester.tap(find.byIcon(Icons.save));
      await tester.pump(const Duration(milliseconds: 300));
      await tester.pump(const Duration(seconds: 1));

      // then
      expect(find.byType(ScoreFormScreen), findsOneWidget);
      expect(find.textContaining('점수 저장에 실패했습니다'), findsOneWidget);
    });
  });
}
