/// Tests unitaires pour GetBudgetTracking use case
library get_budget_tracking_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_tracking.dart';
import 'package:unionflow_mobile_apps/features/finance_workflow/domain/repositories/finance_workflow_repository.dart';
import 'package:unionflow_mobile_apps/core/error/failures.dart';

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

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

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

  group('GetBudgetTracking Use Case', () {
    const tBudgetId = 'budget-123';
    final tTrackingData = {
      'budgetId': tBudgetId,
      'totalPlanned': 5000000.0,
      'totalRealized': 3250000.0,
      'remainingAmount': 1750000.0,
      'realizationRate': 0.65,
      'categories': {
        'contributions': {'planned': 2000000.0, 'realized': 1800000.0, 'rate': 0.9},
        'savings': {'planned': 1500000.0, 'realized': 950000.0, 'rate': 0.63},
        'solidarity': {'planned': 1000000.0, 'realized': 350000.0, 'rate': 0.35},
        'events': {'planned': 500000.0, 'realized': 150000.0, 'rate': 0.3},
      },
    };

    test('should return budget tracking data successfully', () async {
      // Arrange
      when(mockRepository.getBudgetTracking(budgetId: tBudgetId))
          .thenAnswer((_) async => Right(tTrackingData));

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

      // Assert
      expect(result, Right(tTrackingData));
      result.fold(
        (failure) => fail('Should not return failure'),
        (tracking) {
          expect(tracking['budgetId'], equals(tBudgetId));
          expect(tracking['totalPlanned'], equals(5000000.0));
          expect(tracking['realizationRate'], equals(0.65));
        },
      );
      verify(mockRepository.getBudgetTracking(budgetId: tBudgetId));
      verifyNoMoreInteractions(mockRepository);
    });

    test('should return tracking with category breakdown', () async {
      // Arrange
      when(mockRepository.getBudgetTracking(budgetId: tBudgetId))
          .thenAnswer((_) async => Right(tTrackingData));

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

      // Assert
      result.fold(
        (failure) => fail('Should not return failure'),
        (tracking) {
          final categories = tracking['categories'] as Map<String, dynamic>;
          expect(categories.keys, contains('contributions'));
          expect(categories.keys, contains('solidarity'));
          final contribs = categories['contributions'] as Map<String, dynamic>;
          expect(contribs['rate'], equals(0.9));
        },
      );
    });

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

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

    test('should return ServerFailure when repository fails', () async {
      // Arrange
      final tFailure = ServerFailure('Erreur suivi budget');
      when(mockRepository.getBudgetTracking(budgetId: anyNamed('budgetId')))
          .thenAnswer((_) async => Left(tFailure));

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

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