/// Tests unitaires pour RejectTransaction use case
library reject_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/reject_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 'reject_transaction_test.mocks.dart';

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

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

  group('RejectTransaction Use Case', () {
    const tApprovalId = 'approval-123';
    const tReason = 'Montant trop élevé - Budget insuffisant';
    final tRejectedTransaction = TransactionApproval(
      id: tApprovalId,
      transactionId: 'tx-123',
      transactionType: TransactionType.withdrawal,
      amount: 500000.0,
      currency: 'XOF',
      requesterId: 'user-1',
      requesterName: 'Amadou Diallo',
      requiredLevel: ApprovalLevel.level2,
      status: ApprovalStatus.rejected,
      approvers: [],
      createdAt: DateTime(2024, 12, 15),
    );

    test('should reject transaction successfully', () async {
      // Arrange
      when(mockRepository.rejectTransaction(
        approvalId: tApprovalId,
        reason: tReason,
      )).thenAnswer((_) async => Right(tRejectedTransaction));

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

      // Assert
      expect(result, Right(tRejectedTransaction));
      result.fold(
        (failure) => fail('Should not return failure'),
        (approval) {
          expect(approval.id, equals(tApprovalId));
          expect(approval.status, equals(ApprovalStatus.rejected));
        },
      );
      verify(mockRepository.rejectTransaction(
        approvalId: tApprovalId,
        reason: tReason,
      ));
      verifyNoMoreInteractions(mockRepository);
    });

    test('should reject transaction with detailed reason', () async {
      // Arrange
      const detailedReason = 'Refus: Documentation incomplète + montant non justifié';
      when(mockRepository.rejectTransaction(
        approvalId: tApprovalId,
        reason: detailedReason,
      )).thenAnswer((_) async => Right(tRejectedTransaction));

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

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

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

      // 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 ValidationFailure when reason is empty', () async {
      // Act
      final result = await useCase(approvalId: tApprovalId, reason: '   ');

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