/// Tests unitaires pour GetBudgetById use case
library get_budget_by_id_test;

import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:dartz/dartz.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/usecases/get_budget_by_id.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/repositories/finance_workflow_repository.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/entities/budget.dart';
import 'package:unionflow_mobile_apps/core/error/failures.dart';

@GenerateMocks([FinanceWorkflowRepository])
import 'get_budget_by_id_test.mocks.dart';

void main() {
  late GetBudgetById useCase;
  late MockFinanceWorkflowRepository mockRepository;

  setUp(() {
    mockRepository = MockFinanceWorkflowRepository();
    useCase = GetBudgetById(mockRepository);
  });

  group('GetBudgetById Use Case', () {
    const tBudgetId = 'budget-123';
    final tBudget = Budget(
      id: tBudgetId,
      name: 'Budget Annuel 2024',
      description: 'Budget prévisionnel pour l\'année 2024',
      organizationId: 'org-123',
      period: BudgetPeriod.annual,
      year: 2024,
      status: BudgetStatus.active,
      lines: [],
      totalPlanned: 5000000.0,
      totalRealized: 3250000.0,
      currency: 'XOF',
      createdBy: 'user-1',
      createdAt: DateTime(2024, 1, 1),
      startDate: DateTime(2024, 1, 1),
      endDate: DateTime(2024, 12, 31),
    );

    test('should return budget details by ID', () async {
      // Arrange
      when(mockRepository.getBudgetById(tBudgetId))
          .thenAnswer((_) async => Right(tBudget));

      // Act
      final result = await useCase(tBudgetId);

      // Assert
      expect(result, Right(tBudget));
      result.fold(
        (failure) => fail('Should not return failure'),
        (budget) {
          expect(budget.id, equals(tBudgetId));
          expect(budget.name, equals('Budget Annuel 2024'));
          expect(budget.totalPlanned, equals(5000000.0));
        },
      );
      verify(mockRepository.getBudgetById(tBudgetId));
      verifyNoMoreInteractions(mockRepository);
    });

    test('should return budget with realized amount', () async {
      // Arrange
      when(mockRepository.getBudgetById(tBudgetId))
          .thenAnswer((_) async => Right(tBudget));

      // Act
      final result = await useCase(tBudgetId);

      // Assert
      result.fold(
        (failure) => fail('Should not return failure'),
        (budget) {
          expect(budget.totalRealized, equals(3250000.0));
          expect(budget.totalRealized, lessThan(budget.totalPlanned));
        },
      );
    });

    test('should return ValidationFailure when budgetId is empty', () async {
      // Act
      final result = await useCase('');

      // Assert
      result.fold(
        (failure) {
          expect(failure, isA<ValidationFailure>());
        },
        (budget) => fail('Should not return budget'),
      );
      verifyZeroInteractions(mockRepository);
    });

    test('should return ServerFailure when budget not found', () async {
      // Arrange
      final tFailure = ServerFailure('Budget non trouvé');
      when(mockRepository.getBudgetById(any))
          .thenAnswer((_) async => Left(tFailure));

      // Act
      final result = await useCase('nonexistent');

      // Assert
      expect(result, Left(tFailure));
      result.fold(
        (failure) => expect(failure, isA<ServerFailure>()),
        (budget) => fail('Should not return budget'),
      );
    });
  });
}
