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 'package:superport_v2/core/common/models/paginated_result.dart';
import 'package:superport_v2/core/permissions/permission_manager.dart';
import 'package:superport_v2/features/approvals/domain/entities/approval.dart';
import 'package:superport_v2/features/approvals/domain/entities/approval_template.dart';
import 'package:superport_v2/features/approvals/domain/errors/approval_access_denied_exception.dart';
import 'package:superport_v2/features/approvals/domain/repositories/approval_repository.dart';
import 'package:superport_v2/features/approvals/domain/repositories/approval_template_repository.dart';
import 'package:superport_v2/features/approvals/presentation/controllers/approval_controller.dart';
import 'package:superport_v2/features/approvals/presentation/pages/approval_page.dart';
import 'package:superport_v2/features/inventory/lookups/domain/entities/lookup_item.dart';
import 'package:superport_v2/features/inventory/lookups/domain/repositories/inventory_lookup_repository.dart';

class _MockApprovalRepository extends Mock implements ApprovalRepository {}

class _FakeApprovalCreateInput extends Fake implements ApprovalCreateInput {}

class _FakeApprovalUpdateInput extends Fake implements ApprovalUpdateInput {}

class _MockApprovalTemplateRepository extends Mock
    implements ApprovalTemplateRepository {}

class _MockInventoryLookupRepository extends Mock
    implements InventoryLookupRepository {}

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

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();

  setUpAll(() {
    registerFallbackValue(_FakeApprovalCreateInput());
    registerFallbackValue(_FakeApprovalUpdateInput());
  });

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

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

    await tester.pumpWidget(_buildApp(const ApprovalPage()));
    await tester.pump();

    expect(find.text('결재 관리'), findsWidgets);
    expect(find.text('결재 관리 기능 준비 중'), findsOneWidget);
  });

  group('플래그 On', () {
    late _MockApprovalRepository repository;
    late _MockApprovalTemplateRepository templateRepository;
    late _MockInventoryLookupRepository lookupRepository;

    setUp(() {
      dotenv.testLoad(fileInput: 'FEATURE_APPROVALS_ENABLED=true\n');
      repository = _MockApprovalRepository();
      templateRepository = _MockApprovalTemplateRepository();
      lookupRepository = _MockInventoryLookupRepository();
      GetIt.I.registerLazySingleton<ApprovalRepository>(() => repository);
      GetIt.I.registerLazySingleton<ApprovalTemplateRepository>(
        () => templateRepository,
      );
      GetIt.I.registerLazySingleton<InventoryLookupRepository>(
        () => lookupRepository,
      );
      when(
        () => templateRepository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          isActive: any(named: 'isActive'),
        ),
      ).thenAnswer(
        (_) async => PaginatedResult<ApprovalTemplate>(
          items: [],
          page: 1,
          pageSize: 20,
          total: 0,
        ),
      );
      when(
        () => repository.listActions(activeOnly: any(named: 'activeOnly')),
      ).thenAnswer((_) async => const []);
      when(() => lookupRepository.fetchApprovalStatuses()).thenAnswer(
        (_) async => [LookupItem(id: 1, name: '승인대기', code: 'pending')],
      );
      when(
        () => repository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          transactionId: any(named: 'transactionId'),
          approvalStatusId: any(named: 'approvalStatusId'),
          requestedById: any(named: 'requestedById'),
          statusCodes: any(named: 'statusCodes'),
          includePending: any(named: 'includePending'),
          includeHistories: any(named: 'includeHistories'),
          includeSteps: any(named: 'includeSteps'),
        ),
      ).thenAnswer(
        (_) async => PaginatedResult<Approval>(
          items: const [],
          page: 1,
          pageSize: 20,
          total: 0,
        ),
      );
    });

    testWidgets('상태 룩업을 불러와 필터 라벨을 구성한다', (tester) async {
      await tester.pumpWidget(_buildApp(const ApprovalPage()));
      await tester.pumpAndSettle();

      verify(() => lookupRepository.fetchApprovalStatuses()).called(1);
      final statusSelectFinder = find.byKey(
        const ValueKey(ApprovalStatusFilter.all),
      );
      expect(statusSelectFinder, findsOneWidget);
      await tester.tap(statusSelectFinder);
      await tester.pumpAndSettle();
      expect(find.text('승인대기'), findsWidgets);
    });

    testWidgets('접근 거부 시 경고 토스트를 노출한다', (tester) async {
      when(
        () => repository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          transactionId: any(named: 'transactionId'),
          approvalStatusId: any(named: 'approvalStatusId'),
          requestedById: any(named: 'requestedById'),
          statusCodes: any(named: 'statusCodes'),
          includePending: any(named: 'includePending'),
          includeHistories: any(named: 'includeHistories'),
          includeSteps: any(named: 'includeSteps'),
        ),
      ).thenThrow(const ApprovalAccessDeniedException(message: '열람 권한이 없습니다.'));

      await tester.pumpWidget(_buildApp(const ApprovalPage()));
      await tester.pump();
      await tester.pump(const Duration(milliseconds: 50));

      expect(find.text('열람 권한이 없습니다.'), findsWidgets);
    });
  });
}
