import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:shadcn_ui/shadcn_ui.dart';

import 'package:superport_v2/core/network/api_error.dart';
import 'package:superport_v2/core/network/failure.dart';
import 'package:superport_v2/features/util/postal_search/presentation/models/postal_search_result.dart';
import 'package:superport_v2/features/util/postal_search/presentation/widgets/postal_search_dialog.dart';

class _PostalSearchHarness extends StatefulWidget {
  const _PostalSearchHarness({required this.fetcher, this.initialKeyword});

  final PostalSearchFetcher fetcher;
  final String? initialKeyword;

  @override
  State<_PostalSearchHarness> createState() => _PostalSearchHarnessState();
}

class _PostalSearchHarnessState extends State<_PostalSearchHarness> {
  PostalSearchResult? _selection;
  bool _dialogScheduled = false;

  void _ensureDialogShown(BuildContext innerContext) {
    if (_dialogScheduled) {
      return;
    }
    _dialogScheduled = true;
    WidgetsBinding.instance.addPostFrameCallback((_) async {
      final result = await showPostalSearchDialog(
        innerContext,
        fetcher: widget.fetcher,
        initialKeyword: widget.initialKeyword,
      );
      if (!mounted) {
        return;
      }
      setState(() {
        _selection = result;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Builder(
        builder: (innerContext) {
          return ShadTheme(
            data: ShadThemeData(
              colorScheme: const ShadSlateColorScheme.light(),
              brightness: Brightness.light,
            ),
            child: Builder(
              builder: (themeContext) {
                _ensureDialogShown(themeContext);
                return Scaffold(
                  body: Center(
                    child: Text(
                      _selection?.zipcode ?? '선택 없음',
                      key: const Key('selected_zipcode'),
                    ),
                  ),
                );
              },
            ),
          );
        },
      ),
    );
  }
}

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();

  testWidgets('검색 전 안내 문구를 노출하고 fetcher를 호출하지 않는다', (tester) async {
    var called = false;

    await tester.pumpWidget(
      _PostalSearchHarness(
        fetcher: (keyword) async {
          called = true;
          return [];
        },
      ),
    );

    await tester.pumpAndSettle();

    expect(find.text('검색어를 입력한 뒤 엔터 또는 검색 버튼을 눌러 주세요.'), findsOneWidget);
    expect(called, isFalse);
  });

  testWidgets('검색 실행 후 결과를 선택하면 선택 정보가 반환된다', (tester) async {
    var receivedKeyword = '';

    await tester.pumpWidget(
      _PostalSearchHarness(
        fetcher: (keyword) async {
          receivedKeyword = keyword;
          return [
            PostalSearchResult(
              zipcode: '06000',
              sido: '서울특별시',
              sigungu: '강남구',
              roadName: '언주로',
              buildingNumber: '100',
            ),
          ];
        },
      ),
    );

    await tester.pumpAndSettle();

    final inputFinder = find.byType(EditableText);
    expect(inputFinder, findsOneWidget);

    await tester.enterText(inputFinder, '언주로');
    await tester.tap(find.text('검색'));
    await tester.pumpAndSettle();

    expect(receivedKeyword, '언주로');
    expect(find.text('검색 결과 1건'), findsOneWidget);

    await tester.tap(find.text('06000'));
    await tester.pumpAndSettle();

    final selectedFinder = find.byKey(const Key('selected_zipcode'));
    expect(selectedFinder, findsOneWidget);
    final selectedText = tester.widget<Text>(selectedFinder);
    expect(selectedText.data, '06000');
  });

  testWidgets('initialKeyword가 주어지면 자동으로 검색을 수행한다', (tester) async {
    String? receivedKeyword;

    await tester.pumpWidget(
      _PostalSearchHarness(
        fetcher: (keyword) async {
          receivedKeyword = keyword;
          return [];
        },
        initialKeyword: '06236',
      ),
    );

    await tester.pumpAndSettle();

    expect(receivedKeyword, '06236');

    await tester.tap(find.text('닫기'));
    await tester.pumpAndSettle();
  });

  testWidgets('검색 실패 시 Failure 메시지를 표시한다', (tester) async {
    final exception = ApiException(
      code: ApiErrorCode.unprocessableEntity,
      message: '우편번호 검색에 실패했습니다.',
      details: {
        'errors': {
          'keyword': ['검색어를 다시 확인해 주세요.'],
        },
      },
    );

    await tester.pumpWidget(
      _PostalSearchHarness(
        fetcher: (_) => Future<List<PostalSearchResult>>.error(exception),
      ),
    );

    await tester.pumpAndSettle();

    final inputFinder = find.byType(EditableText);
    await tester.enterText(inputFinder, '강남대로');
    await tester.tap(find.text('검색'));
    await tester.pumpAndSettle();

    final failure = Failure.from(exception);
    expect(find.text(failure.describe()), findsOneWidget);
  });
}
