import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';

import 'package:superport_v2/core/common/models/paginated_result.dart';
import 'package:superport_v2/features/masters/vendor/domain/entities/vendor.dart';
import 'package:superport_v2/features/masters/vendor/domain/repositories/vendor_repository.dart';
import 'package:superport_v2/features/masters/vendor/presentation/controllers/vendor_controller.dart';

class _MockVendorRepository extends Mock implements VendorRepository {}

class _FakeVendorInput extends Fake implements VendorInput {}

void main() {
  late VendorController controller;
  late _MockVendorRepository repository;

  final sampleVendor = Vendor(
    id: 1,
    vendorCode: 'V-001',
    vendorName: '슈퍼벤더',
    isActive: true,
    isDeleted: false,
  );

  PaginatedResult<Vendor> createResult({List<Vendor>? items}) {
    final list = items ?? [sampleVendor];
    return PaginatedResult<Vendor>(
      items: list,
      page: 1,
      pageSize: 20,
      total: list.length,
    );
  }

  setUpAll(() {
    registerFallbackValue(_FakeVendorInput());
  });

  setUp(() {
    repository = _MockVendorRepository();
    controller = VendorController(repository: repository);
  });

  group('fetch', () {
    test('정상 조회 시 결과가 저장된다', () async {
      when(
        () => repository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          isActive: any(named: 'isActive'),
        ),
      ).thenAnswer((_) async => createResult());

      await controller.fetch();

      expect(controller.isLoading, isFalse);
      expect(controller.errorMessage, isNull);
      expect(controller.result?.items, isNotEmpty);
      verify(
        () =>
            repository.list(page: 1, pageSize: 20, query: null, isActive: null),
      ).called(1);
    });

    test('에러 발생 시 errorMessage가 세팅된다', () async {
      when(
        () => repository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          isActive: any(named: 'isActive'),
        ),
      ).thenThrow(Exception('fail'));

      await controller.fetch();

      expect(controller.isLoading, isFalse);
      expect(controller.errorMessage, isNotNull);
    });
  });

  test('updateQuery / updateStatusFilter 변경 시 상태 반영', () {
    controller.updateQuery('abc');
    controller.updateStatusFilter(VendorStatusFilter.activeOnly);

    expect(controller.query, 'abc');
    expect(controller.statusFilter, VendorStatusFilter.activeOnly);
  });

  group('create/update/delete/restore', () {
    setUp(() {
      when(
        () => repository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          isActive: any(named: 'isActive'),
        ),
      ).thenAnswer((_) async => createResult());
    });

    test('create 성공 시 목록을 새로고침한다', () async {
      when(
        () => repository.create(any()),
      ).thenAnswer((_) async => sampleVendor);

      final result = await controller.create(
        VendorInput(vendorCode: 'V-001', vendorName: '슈퍼벤더'),
      );

      expect(result, isNotNull);
      expect(controller.result?.items.length, 1);
      verify(() => repository.create(any())).called(1);
      verify(
        () =>
            repository.list(page: 1, pageSize: 20, query: null, isActive: null),
      ).called(1);
    });

    test('update 성공 시 현재 페이지를 유지하며 갱신한다', () async {
      when(
        () => repository.update(any(), any()),
      ).thenAnswer((_) async => sampleVendor);

      final result = await controller.update(
        1,
        VendorInput(vendorCode: 'V-001', vendorName: '슈퍼벤더'),
      );

      expect(result, isNotNull);
      expect(controller.result?.items, isNotEmpty);
      verify(() => repository.update(1, any())).called(1);
    });

    test('delete 성공 시 fetch가 재호출된다', () async {
      when(() => repository.delete(any())).thenAnswer((_) async {});

      final result = await controller.delete(1);

      expect(result, isTrue);
      verify(() => repository.delete(1)).called(1);
    });

    test('restore 성공 시 fetch가 재호출된다', () async {
      when(
        () => repository.restore(any()),
      ).thenAnswer((_) async => sampleVendor);

      final restored = await controller.restore(1);

      expect(restored, isNotNull);
      verify(() => repository.restore(1)).called(1);
    });
  });
}
