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/menu/domain/entities/menu.dart';
import 'package:superport_v2/features/masters/menu/domain/repositories/menu_repository.dart';
import 'package:superport_v2/features/masters/menu/presentation/controllers/menu_controller.dart';

class _MockMenuRepository extends Mock implements MenuRepository {}

class _FakeMenuInput extends Fake implements MenuInput {}

void main() {
  late MenuController controller;
  late _MockMenuRepository repository;

  final sampleMenu = MenuItem(
    id: 1,
    menuCode: 'MENU001',
    menuName: '대시보드',
    isActive: true,
    isDeleted: false,
  );

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

  setUpAll(() {
    registerFallbackValue(_FakeMenuInput());
  });

  setUp(() {
    repository = _MockMenuRepository();
    controller = MenuController(repository: repository);
  });

  group('loadParents', () {
    test('상위 메뉴를 로드한다', () async {
      when(
        () => repository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          parentId: any(named: 'parentId'),
          isActive: any(named: 'isActive'),
          includeDeleted: any(named: 'includeDeleted'),
        ),
      ).thenAnswer((_) async => createResult());

      await controller.loadParents();

      expect(controller.parents, isNotEmpty);
      verify(
        () => repository.list(
          page: 1,
          pageSize: any<int>(named: 'pageSize'),
          query: null,
          parentId: null,
          isActive: null,
          includeDeleted: false,
        ),
      ).called(1);
    });
  });

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

      await controller.fetch();

      expect(controller.result?.items, isNotEmpty);
      expect(controller.errorMessage, isNull);
    });

    test('필터 조건 적용', () async {
      when(
        () => repository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          parentId: any(named: 'parentId'),
          isActive: any(named: 'isActive'),
          includeDeleted: any(named: 'includeDeleted'),
        ),
      ).thenAnswer((_) async => createResult());

      controller.updateQuery('dash');
      controller.updateParentFilter(10);
      controller.updateStatusFilter(MenuStatusFilter.activeOnly);
      controller.updateIncludeDeleted(true);

      await controller.fetch(page: 2);

      verify(
        () => repository.list(
          page: 2,
          pageSize: 20,
          query: 'dash',
          parentId: 10,
          isActive: true,
          includeDeleted: true,
        ),
      ).called(1);
    });

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

      await controller.fetch();

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

  test('필터 업데이트', () {
    controller.updateQuery('code');
    controller.updateParentFilter(1);
    controller.updateStatusFilter(MenuStatusFilter.inactiveOnly);
    controller.updateIncludeDeleted(true);

    expect(controller.query, 'code');
    expect(controller.parentFilter, 1);
    expect(controller.statusFilter, MenuStatusFilter.inactiveOnly);
    expect(controller.includeDeleted, isTrue);
  });

  group('mutations', () {
    setUp(() {
      when(
        () => repository.list(
          page: any(named: 'page'),
          pageSize: any(named: 'pageSize'),
          query: any(named: 'query'),
          parentId: any(named: 'parentId'),
          isActive: any(named: 'isActive'),
          includeDeleted: any(named: 'includeDeleted'),
        ),
      ).thenAnswer((_) async => createResult());
    });

    final input = MenuInput(menuCode: 'MENU001', menuName: '대시보드');

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

      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 => sampleMenu);

      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 => sampleMenu);

      final restored = await controller.restore(1);

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