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

import '../../../../../helpers/tester_extensions.dart';
import 'package:superport_v2/core/common/models/paginated_result.dart';
import 'package:superport_v2/features/masters/warehouse/domain/entities/warehouse.dart';
import 'package:superport_v2/features/masters/warehouse/domain/repositories/warehouse_repository.dart';
import 'package:superport_v2/features/masters/warehouse/presentation/pages/warehouse_page.dart';
import 'package:superport_v2/features/util/postal_search/domain/entities/postal_code.dart';
import 'package:superport_v2/features/util/postal_search/domain/repositories/postal_search_repository.dart';

class _MockWarehouseRepository extends Mock implements WarehouseRepository {}

class _FakeWarehouseInput extends Fake implements WarehouseInput {}

class _MockPostalSearchRepository extends Mock
    implements PostalSearchRepository {}

Widget _buildApp(Widget child) {
  return MaterialApp(
    home: ShadTheme(
      data: ShadThemeData(
        colorScheme: const ShadSlateColorScheme.light(),
        brightness: Brightness.light,
      ),
      child: Scaffold(body: child),
    ),
  );
}

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();

  setUpAll(() {
    registerFallbackValue(_FakeWarehouseInput());
  });

  tearDown(() async {
    await GetIt.I.reset();
    dotenv.clean();
  });

  testWidgets('플래그 Off 시 스펙 화면', (tester) async {
    dotenv.testLoad(fileInput: 'FEATURE_WAREHOUSES_ENABLED=false\n');

    await tester.pumpWidget(
      _buildApp(WarehousePage(routeUri: Uri(path: '/masters/warehouses'))),
    );
    await tester.pump();

    expect(find.text('입고지(창고) 관리'), findsOneWidget);
    expect(find.text('테이블 리스트'), findsOneWidget);
  });

  group('플래그 On', () {
    late _MockWarehouseRepository repository;
    late _MockPostalSearchRepository postalRepository;

    setUp(() {
      dotenv.testLoad(fileInput: 'FEATURE_WAREHOUSES_ENABLED=true\n');
      repository = _MockWarehouseRepository();
      postalRepository = _MockPostalSearchRepository();
      GetIt.I.registerLazySingleton<WarehouseRepository>(() => repository);
      GetIt.I.registerLazySingleton<PostalSearchRepository>(
        () => postalRepository,
      );
      when(
        () => postalRepository.search(
          keyword: any(named: 'keyword'),
          limit: any(named: 'limit'),
        ),
      ).thenAnswer(
        (_) async => [
          PostalCode(
            zipcode: '06000',
            sido: '서울특별시',
            sigungu: '강남구',
            roadName: '테헤란로',
            buildingMainNo: 100,
          ),
        ],
      );
    });

    testWidgets('목록 조회 후 테이블 표시', (tester) async {
      when(
        () => repository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          isActive: any(named: 'isActive'),
          includeZipcode: any(named: 'includeZipcode'),
        ),
      ).thenAnswer(
        (_) async => PaginatedResult<Warehouse>(
          items: [
            Warehouse(
              id: 1,
              warehouseCode: 'WH-001',
              warehouseName: '서울 창고',
              zipcode: WarehouseZipcode(zipcode: '06000'),
            ),
          ],
          page: 1,
          pageSize: 20,
          total: 1,
        ),
      );

      await tester.pumpWidget(
        _buildApp(WarehousePage(routeUri: Uri(path: '/masters/warehouses'))),
      );
      await tester.pumpAndSettle();

      expect(find.text('WH-001'), findsOneWidget);
      verify(
        () => repository.list(
          page: 1,
          pageSize: 20,
          query: null,
          isActive: null,
          includeZipcode: true,
        ),
      ).called(1);
    });

    testWidgets('폼 검증: 필수값 누락', (tester) async {
      when(
        () => repository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          isActive: any(named: 'isActive'),
          includeZipcode: any(named: 'includeZipcode'),
        ),
      ).thenAnswer(
        (_) async => PaginatedResult<Warehouse>(
          items: const [],
          page: 1,
          pageSize: 20,
          total: 0,
        ),
      );

      await tester.pumpWidget(
        _buildApp(WarehousePage(routeUri: Uri(path: '/masters/warehouses'))),
      );
      await tester.pumpAndSettle();

      await tester.tap(find.text('신규 등록'));
      await tester.pumpAndSettle();
      await tester.tapShadButton('등록', settle: false);
      await tester.pump();

      expect(find.text('창고코드를 입력하세요.'), findsOneWidget);
      expect(find.text('창고명을 입력하세요.'), findsOneWidget);
    });

    testWidgets('신규 등록 성공', (tester) async {
      var listCallCount = 0;
      when(
        () => repository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          isActive: any(named: 'isActive'),
        ),
      ).thenAnswer((_) async {
        listCallCount += 1;
        if (listCallCount == 1) {
          return PaginatedResult<Warehouse>(
            items: const [],
            page: 1,
            pageSize: 20,
            total: 0,
          );
        }
        return PaginatedResult<Warehouse>(
          items: [
            Warehouse(
              id: 7,
              warehouseCode: 'WH-100',
              warehouseName: '신규 창고',
              zipcode: WarehouseZipcode(zipcode: '12345'),
            ),
          ],
          page: 1,
          pageSize: 20,
          total: 1,
        );
      });

      WarehouseInput? capturedInput;
      when(() => repository.create(any())).thenAnswer((invocation) async {
        capturedInput = invocation.positionalArguments.first as WarehouseInput;
        return Warehouse(
          id: 7,
          warehouseCode: capturedInput!.warehouseCode,
          warehouseName: capturedInput!.warehouseName,
        );
      });

      await tester.pumpWidget(
        _buildApp(WarehousePage(routeUri: Uri(path: '/masters/warehouses'))),
      );
      await tester.pumpAndSettle();

      await tester.tap(find.text('신규 등록'));
      await tester.pumpAndSettle();

      final fields = find.descendant(
        of: find.byType(Dialog),
        matching: find.byType(EditableText),
      );

      await tester.enterText(fields.at(0), 'WH-100');
      await tester.enterText(fields.at(1), '신규 창고');
      await tester.enterText(fields.at(2), '06000');
      await tester.tap(
        find.descendant(
          of: find.byType(Dialog),
          matching: find.widgetWithText(ShadButton, '검색'),
        ),
      );
      await tester.pumpAndSettle();

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

      final updatedFields = find.descendant(
        of: find.byType(Dialog),
        matching: find.byType(EditableText),
      );

      await tester.enterText(updatedFields.at(3), '주소');

      await tester.tapShadButton('등록');

      expect(capturedInput, isNotNull);
      expect(capturedInput?.warehouseCode, 'WH-100');
      expect(capturedInput?.zipcode, '06000');
      expect(find.byType(Dialog), findsNothing);
      expect(find.text('WH-100'), findsOneWidget);
      verify(() => repository.create(any())).called(1);
    });

    testWidgets('좁은 폭에서도 오버플로 없이 렌더링', (tester) async {
      when(
        () => repository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          isActive: any(named: 'isActive'),
          includeZipcode: any(named: 'includeZipcode'),
        ),
      ).thenAnswer(
        (_) async => PaginatedResult<Warehouse>(
          items: [
            Warehouse(
              id: 1,
              warehouseCode: 'WH-SMALL',
              warehouseName: '좁은 화면 창고',
              zipcode: WarehouseZipcode(zipcode: '06000'),
            ),
          ],
          page: 1,
          pageSize: 20,
          total: 1,
        ),
      );

      await tester.pumpWidget(
        _buildApp(
          Center(
            child: SizedBox(
              width: 320,
              child: WarehousePage(routeUri: Uri(path: '/masters/warehouses')),
            ),
          ),
        ),
      );
      await tester.pumpAndSettle();

      expect(tester.takeException(), isNull);
    });
  });
}
