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/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/controllers/warehouse_controller.dart';

class _MockWarehouseRepository extends Mock implements WarehouseRepository {}

class _FakeWarehouseInput extends Fake implements WarehouseInput {}

void main() {
  late WarehouseController controller;
  late _MockWarehouseRepository repository;

  final sampleWarehouse = Warehouse(
    id: 1,
    warehouseCode: 'WH-001',
    warehouseName: '테스트 창고',
    zipcode: WarehouseZipcode(zipcode: '06000'),
  );

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

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

  setUp(() {
    repository = _MockWarehouseRepository();
    controller = WarehouseController(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'),
          includeZipcode: any(named: 'includeZipcode'),
        ),
      ).thenAnswer((_) async => createResult());

      await controller.fetch();

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

    test('에러 발생 시 errorMessage 설정', () async {
      when(
        () => repository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          isActive: any(named: 'isActive'),
          includeZipcode: any(named: 'includeZipcode'),
        ),
      ).thenThrow(Exception('fail'));

      await controller.fetch();

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

  test('쿼리/필터 업데이트 반영', () {
    controller.updateQuery('abc');
    controller.updateStatusFilter(WarehouseStatusFilter.inactiveOnly);

    expect(controller.query, 'abc');
    expect(controller.statusFilter, WarehouseStatusFilter.inactiveOnly);
  });

  group('mutations', () {
    setUp(() {
      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 => createResult());
    });

    final input = WarehouseInput(
      warehouseCode: 'WH-001',
      warehouseName: '테스트 창고',
    );

    test('create 성공', () async {
      when(
        () => repository.create(any()),
      ).thenAnswer((_) async => sampleWarehouse);

      final created = await controller.create(input);

      expect(created, isNotNull);
      verify(() => repository.create(any())).called(1);
    });

    test('update 성공', () async {
      when(
        () => repository.update(any(), any()),
      ).thenAnswer((_) async => sampleWarehouse);

      final updated = await controller.update(1, input);

      expect(updated, isNotNull);
      verify(() => repository.update(1, any())).called(1);
    });

    test('delete 성공', () async {
      when(() => repository.delete(any())).thenAnswer((_) async {});

      final success = await controller.delete(1);

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

    test('restore 성공', () async {
      when(
        () => repository.restore(any()),
      ).thenAnswer((_) async => sampleWarehouse);

      final restored = await controller.restore(1);

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