/// Tests unitaires pour ApproveTransaction use case
library approve_transaction_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/approve_transaction.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/transaction_approval.dart';
import 'package:unionflow_mobile_apps/core/error/failures.dart';

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

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

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

  group('ApproveTransaction Use Case', () {
    const tApprovalId = 'approval-123';
    const tComment = 'Approuvé - Montant conforme au budget';
    final tApprovedTransaction = TransactionApproval(
      id: tApprovalId,
      transactionId: 'tx-123',
      transactionType: TransactionType.withdrawal,
      amount: 500000.0,
      currency: 'XOF',
      requesterId: 'user-1',
      requesterName: 'Amadou Diallo',
      requiredLevel: ApprovalLevel.level1,
      status: ApprovalStatus.approved,
      approvers: [],
      createdAt: DateTime(2024, 12, 15),
    );

    test('should approve transaction successfully', () async {
      // Arrange
      when(mockRepository.approveTransaction(
        approvalId: tApprovalId,
        comment: tComment,
      )).thenAnswer((_) async => Right(tApprovedTransaction));

      // Act
      final result = await useCase(approvalId: tApprovalId, comment: tComment);

      // Assert
      expect(result, Right(tApprovedTransaction));
      result.fold(
        (failure) => fail('Should not return failure'),
        (approval) {
          expect(approval.id, equals(tApprovalId));
          expect(approval.status, equals(ApprovalStatus.approved));
        },
      );
      verify(mockRepository.approveTransaction(
        approvalId: tApprovalId,
        comment: tComment,
      ));
      verifyNoMoreInteractions(mockRepository);
    });

    test('should approve transaction without comment', () async {
      // Arrange
      when(mockRepository.approveTransaction(
        approvalId: tApprovalId,
        comment: null,
      )).thenAnswer((_) async => Right(tApprovedTransaction));

      // Act
      final result = await useCase(approvalId: tApprovalId);

      // Assert
      result.fold(
        (failure) => fail('Should not return failure'),
        (approval) => expect(approval.status, equals(ApprovalStatus.approved)),
      );
    });

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

      // Assert
      result.fold(
        (failure) {
          expect(failure, isA<ValidationFailure>());
          expect((failure as ValidationFailure).message, contains('ID approbation requis'));
        },
        (approval) => fail('Should not return approval'),
      );
      verifyZeroInteractions(mockRepository);
    });

    test('should return ServerFailure when repository fails', () async {
      // Arrange
      final tFailure = ServerFailure('Transaction déjà approuvée');
      when(mockRepository.approveTransaction(
        approvalId: anyNamed('approvalId'),
        comment: anyNamed('comment'),
      )).thenAnswer((_) async => Left(tFailure));

      // Act
      final result = await useCase(approvalId: tApprovalId);

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