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/product/domain/entities/product.dart';
import 'package:superport_v2/features/masters/product/domain/repositories/product_repository.dart';
import 'package:superport_v2/features/masters/product/presentation/pages/product_page.dart';
import 'package:superport_v2/features/masters/uom/domain/entities/uom.dart';
import 'package:superport_v2/features/masters/uom/domain/repositories/uom_repository.dart';
import 'package:superport_v2/features/masters/vendor/domain/entities/vendor.dart';
import 'package:superport_v2/features/masters/vendor/domain/repositories/vendor_repository.dart';

class _MockProductRepository extends Mock implements ProductRepository {}

class _MockVendorRepository extends Mock implements VendorRepository {}

class _MockUomRepository extends Mock implements UomRepository {}

class _FakeProductInput extends Fake implements ProductInput {}

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(_FakeProductInput());
  });

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

  testWidgets('플래그 Off 시 스펙 문서 화면을 노출한다', (tester) async {
    dotenv.testLoad(fileInput: 'FEATURE_PRODUCTS_ENABLED=false\n');

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

    expect(find.text('장비 모델(제품) 관리'), findsOneWidget);
    expect(find.text('테이블 리스트'), findsOneWidget);
  });

  group('플래그 On 환경', () {
    late _MockProductRepository productRepository;
    late _MockVendorRepository vendorRepository;
    late _MockUomRepository uomRepository;

    setUp(() {
      dotenv.testLoad(fileInput: 'FEATURE_PRODUCTS_ENABLED=true\n');
      productRepository = _MockProductRepository();
      vendorRepository = _MockVendorRepository();
      uomRepository = _MockUomRepository();
      GetIt.I.registerLazySingleton<ProductRepository>(() => productRepository);
      GetIt.I.registerLazySingleton<VendorRepository>(() => vendorRepository);
      GetIt.I.registerLazySingleton<UomRepository>(() => uomRepository);

      when(
        () => vendorRepository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          isActive: any(named: 'isActive'),
        ),
      ).thenAnswer(
        (_) async => PaginatedResult<Vendor>(
          items: [Vendor(id: 1, vendorCode: 'V-001', vendorName: '슈퍼벤더')],
          page: 1,
          pageSize: 20,
          total: 1,
        ),
      );

      when(
        () => uomRepository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          isActive: any(named: 'isActive'),
        ),
      ).thenAnswer(
        (_) async => PaginatedResult<Uom>(
          items: [Uom(id: 5, uomName: 'EA')],
          page: 1,
          pageSize: 20,
          total: 1,
        ),
      );
    });

    testWidgets('목록 조회 후 테이블에 표시한다', (tester) async {
      when(
        () => productRepository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          vendorId: any(named: 'vendorId'),
          uomId: any(named: 'uomId'),
          isActive: any(named: 'isActive'),
        ),
      ).thenAnswer(
        (_) async => PaginatedResult<Product>(
          items: [
            Product(
              id: 1,
              productCode: 'P-001',
              productName: '테스트 제품',
              vendor: ProductVendor(
                id: 1,
                vendorCode: 'V-001',
                vendorName: '슈퍼벤더',
              ),
              uom: ProductUom(id: 5, uomName: 'EA'),
            ),
          ],
          page: 1,
          pageSize: 20,
          total: 1,
        ),
      );

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

      expect(find.text('P-001'), findsOneWidget);
      verify(
        () => productRepository.list(
          page: 1,
          pageSize: 20,
          query: null,
          vendorId: null,
          uomId: null,
          isActive: null,
        ),
      ).called(1);
    });

    testWidgets('목록이 비어 있으면 안내 문구를 표시한다', (tester) async {
      when(
        () => productRepository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          vendorId: any(named: 'vendorId'),
          uomId: any(named: 'uomId'),
          isActive: any(named: 'isActive'),
        ),
      ).thenAnswer(
        (_) async => PaginatedResult<Product>(
          items: const [],
          page: 1,
          pageSize: 20,
          total: 0,
        ),
      );

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

      expect(find.text('조건에 맞는 제품이 없습니다.'), findsOneWidget);
    });

    testWidgets('폼 검증: 필수값 미입력 시 에러 메시지를 표시한다', (tester) async {
      when(
        () => productRepository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          vendorId: any(named: 'vendorId'),
          uomId: any(named: 'uomId'),
          isActive: any(named: 'isActive'),
        ),
      ).thenAnswer(
        (_) async => PaginatedResult<Product>(
          items: const [],
          page: 1,
          pageSize: 20,
          total: 0,
        ),
      );

      await tester.pumpWidget(
        _buildApp(ProductPage(routeUri: Uri(path: '/masters/products'))),
      );
      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);
      expect(find.text('제조사를 선택하세요.'), findsOneWidget);
      expect(find.text('단위를 선택하세요.'), findsOneWidget);
    });

    testWidgets('신규 등록 성공 시 repository.create 호출', (tester) async {
      var listCallCount = 0;
      when(
        () => productRepository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          vendorId: any(named: 'vendorId'),
          uomId: any(named: 'uomId'),
          isActive: any(named: 'isActive'),
        ),
      ).thenAnswer((_) async {
        listCallCount += 1;
        if (listCallCount == 1) {
          return PaginatedResult<Product>(
            items: const [],
            page: 1,
            pageSize: 20,
            total: 0,
          );
        }
        return PaginatedResult<Product>(
          items: [
            Product(
              id: 99,
              productCode: 'NP-001',
              productName: '신규 제품',
              vendor: ProductVendor(
                id: 1,
                vendorCode: 'V-001',
                vendorName: '슈퍼벤더',
              ),
              uom: ProductUom(id: 5, uomName: 'EA'),
            ),
          ],
          page: 1,
          pageSize: 20,
          total: 1,
        );
      });

      ProductInput? capturedInput;
      when(() => productRepository.create(any())).thenAnswer((
        invocation,
      ) async {
        capturedInput = invocation.positionalArguments.first as ProductInput;
        return Product(
          id: 99,
          productCode: capturedInput!.productCode,
          productName: capturedInput!.productName,
          vendor: ProductVendor(
            id: capturedInput!.vendorId,
            vendorCode: 'V',
            vendorName: '슈퍼벤더',
          ),
          uom: ProductUom(id: capturedInput!.uomId, uomName: 'EA'),
        );
      });

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

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

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

      await tester.enterText(editableTexts.at(0), 'NP-001');
      await tester.enterText(editableTexts.at(1), '신규 제품');

      await tester.tap(find.text('제조사를 선택하세요'));
      await tester.pumpAndSettle();
      await tester.tap(find.text('슈퍼벤더 (V-001)'));
      await tester.pumpAndSettle();

      await tester.tap(find.text('단위를 선택하세요'));
      await tester.pumpAndSettle();
      await tester.tap(find.text('EA'));
      await tester.pumpAndSettle();

      await tester.tapShadButton('등록');

      expect(capturedInput, isNotNull);
      expect(capturedInput?.productCode, 'NP-001');
      expect(find.byType(Dialog), findsNothing);
      expect(find.text('NP-001'), findsOneWidget);
      verify(() => productRepository.create(any())).called(1);
    });

    testWidgets('좁은 폭에서도 오버플로 없이 렌더링', (tester) async {
      when(
        () => productRepository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          vendorId: any(named: 'vendorId'),
          uomId: any(named: 'uomId'),
          isActive: any(named: 'isActive'),
        ),
      ).thenAnswer(
        (_) async => PaginatedResult<Product>(
          items: [
            Product(
              id: 1,
              productCode: 'P-SMALL',
              productName: '좁은 화면 제품',
              vendor: ProductVendor(
                id: 1,
                vendorCode: 'V-001',
                vendorName: '슈퍼벤더',
              ),
              uom: ProductUom(id: 5, uomName: 'EA'),
            ),
          ],
          page: 1,
          pageSize: 20,
          total: 1,
        ),
      );

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

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