/// Implémentation du repository de workflow financier
library finance_workflow_repository_impl;

import 'dart:async';
import 'package:dartz/dartz.dart';
import 'package:injectable/injectable.dart';
import '../../../../core/error/exceptions.dart';
import '../../../../core/error/failures.dart';
import '../../../../core/network/network_info.dart';
import '../../../../core/network/retry_policy.dart';
import '../../../../core/network/offline_manager.dart';
import '../../domain/entities/budget.dart';
import '../../domain/entities/financial_audit_log.dart';
import '../../domain/entities/transaction_approval.dart';
import '../../domain/repositories/finance_workflow_repository.dart';
import '../datasources/finance_workflow_remote_datasource.dart';

@LazySingleton(as: FinanceWorkflowRepository)
class FinanceWorkflowRepositoryImpl implements FinanceWorkflowRepository {
  final FinanceWorkflowRemoteDatasource remoteDatasource;
  final NetworkInfo networkInfo;
  final OfflineManager offlineManager;
  final RetryPolicy _retryPolicy;

  FinanceWorkflowRepositoryImpl({
    required this.remoteDatasource,
    required this.networkInfo,
    required this.offlineManager,
  }) : _retryPolicy = RetryPolicy(config: RetryConfig.standard);

  @override
  Future<Either<Failure, List<TransactionApproval>>> getPendingApprovals({
    String? organizationId,
  }) async {
    if (!await networkInfo.isConnected) {
      return Left(NetworkFailure('Pas de connexion Internet'));
    }

    try {
      final approvals = await _retryPolicy.execute(
        operation: () => remoteDatasource.getPendingApprovals(
          organizationId: organizationId,
        ),
        shouldRetry: (error) => _isRetryableError(error),
      );
      return Right(approvals);
    } on UnauthorizedException {
      return Left(UnauthorizedFailure('Session expirée'));
    } on ServerException catch (e) {
      return Left(ServerFailure(e.message));
    } on TimeoutException {
      return Left(NetworkFailure('Délai d\'attente dépassé'));
    } catch (e) {
      return Left(UnexpectedFailure('Erreur inattendue: $e'));
    }
  }

  @override
  Future<Either<Failure, TransactionApproval>> getApprovalById(
      String approvalId) async {
    if (!await networkInfo.isConnected) {
      return Left(NetworkFailure('Pas de connexion Internet'));
    }

    try {
      final approval = await _retryPolicy.execute(
        operation: () => remoteDatasource.getApprovalById(approvalId),
        shouldRetry: (error) => _isRetryableError(error),
      );
      return Right(approval);
    } on NotFoundException {
      return Left(NotFoundFailure('Approbation non trouvée'));
    } on UnauthorizedException {
      return Left(UnauthorizedFailure('Session expirée'));
    } on ServerException catch (e) {
      return Left(ServerFailure(e.message));
    } on TimeoutException {
      return Left(NetworkFailure('Délai d\'attente dépassé'));
    } catch (e) {
      return Left(UnexpectedFailure('Erreur inattendue: $e'));
    }
  }

  @override
  Future<Either<Failure, TransactionApproval>> approveTransaction({
    required String approvalId,
    String? comment,
  }) async {
    if (!await networkInfo.isConnected) {
      // Queue for retry when back online
      await offlineManager.queueOperation(
        operationType: 'approveTransaction',
        endpoint: '/api/finance/approvals/$approvalId/approve',
        data: {'approvalId': approvalId, 'comment': comment},
      );
      return Left(NetworkFailure('Pas de connexion Internet. Opération mise en attente.'));
    }

    try {
      final approval = await _retryPolicy.execute(
        operation: () => remoteDatasource.approveTransaction(
          approvalId: approvalId,
          comment: comment,
        ),
        shouldRetry: (error) => _isRetryableError(error),
      );
      return Right(approval);
    } on ForbiddenException catch (e) {
      return Left(ForbiddenFailure(e.message));
    } on UnauthorizedException {
      return Left(UnauthorizedFailure('Session expirée'));
    } on ServerException catch (e) {
      return Left(ServerFailure(e.message));
    } on TimeoutException {
      return Left(NetworkFailure('Délai d\'attente dépassé'));
    } catch (e) {
      return Left(UnexpectedFailure('Erreur inattendue: $e'));
    }
  }

  @override
  Future<Either<Failure, TransactionApproval>> rejectTransaction({
    required String approvalId,
    required String reason,
  }) async {
    if (!await networkInfo.isConnected) {
      // Queue for retry when back online
      await offlineManager.queueOperation(
        operationType: 'rejectTransaction',
        endpoint: '/api/finance/approvals/$approvalId/reject',
        data: {'approvalId': approvalId, 'reason': reason},
      );
      return Left(NetworkFailure('Pas de connexion Internet. Opération mise en attente.'));
    }

    try {
      final approval = await _retryPolicy.execute(
        operation: () => remoteDatasource.rejectTransaction(
          approvalId: approvalId,
          reason: reason,
        ),
        shouldRetry: (error) => _isRetryableError(error),
      );
      return Right(approval);
    } on ForbiddenException catch (e) {
      return Left(ForbiddenFailure(e.message));
    } on UnauthorizedException {
      return Left(UnauthorizedFailure('Session expirée'));
    } on ServerException catch (e) {
      return Left(ServerFailure(e.message));
    } on TimeoutException {
      return Left(NetworkFailure('Délai d\'attente dépassé'));
    } catch (e) {
      return Left(UnexpectedFailure('Erreur inattendue: $e'));
    }
  }

  @override
  Future<Either<Failure, List<Budget>>> getBudgets({
    String? organizationId,
    BudgetStatus? status,
    int? year,
  }) async {
    if (!await networkInfo.isConnected) {
      return Left(NetworkFailure('Pas de connexion Internet'));
    }

    try {
      final budgets = await _retryPolicy.execute(
        operation: () => remoteDatasource.getBudgets(
          organizationId: organizationId,
          status: status?.name,
          year: year,
        ),
        shouldRetry: (error) => _isRetryableError(error),
      );
      return Right(budgets);
    } on UnauthorizedException {
      return Left(UnauthorizedFailure('Session expirée'));
    } on ServerException catch (e) {
      return Left(ServerFailure(e.message));
    } on TimeoutException {
      return Left(NetworkFailure('Délai d\'attente dépassé'));
    } catch (e) {
      return Left(UnexpectedFailure('Erreur inattendue: $e'));
    }
  }

  @override
  Future<Either<Failure, Budget>> getBudgetById(String budgetId) async {
    if (!await networkInfo.isConnected) {
      return Left(NetworkFailure('Pas de connexion Internet'));
    }

    try {
      final budget = await _retryPolicy.execute(
        operation: () => remoteDatasource.getBudgetById(budgetId),
        shouldRetry: (error) => _isRetryableError(error),
      );
      return Right(budget);
    } on NotFoundException {
      return Left(NotFoundFailure('Budget non trouvé'));
    } on UnauthorizedException {
      return Left(UnauthorizedFailure('Session expirée'));
    } on ServerException catch (e) {
      return Left(ServerFailure(e.message));
    } on TimeoutException {
      return Left(NetworkFailure('Délai d\'attente dépassé'));
    } catch (e) {
      return Left(UnexpectedFailure('Erreur inattendue: $e'));
    }
  }

  @override
  Future<Either<Failure, Budget>> createBudget({
    required String name,
    String? description,
    required String organizationId,
    required BudgetPeriod period,
    required int year,
    int? month,
    required List<BudgetLine> lines,
  }) async {
    if (!await networkInfo.isConnected) {
      // Queue for retry when back online
      await offlineManager.queueOperation(
        operationType: 'createBudget',
        endpoint: '/api/finance/budgets',
        data: {
          'name': name,
          'description': description,
          'organizationId': organizationId,
          'period': period.name,
          'year': year,
          'month': month,
          'lines': lines.map((line) => {
            'id': line.id,
            'category': line.category.name,
            'name': line.name,
            'description': line.description,
            'amountPlanned': line.amountPlanned,
            'amountRealized': line.amountRealized,
            'notes': line.notes,
          }).toList(),
        },
      );
      return Left(NetworkFailure('Pas de connexion Internet. Opération mise en attente.'));
    }

    try {
      final budget = await _retryPolicy.execute(
        operation: () => remoteDatasource.createBudget(
          name: name,
          description: description,
          organizationId: organizationId,
          period: period.name,
          year: year,
          month: month,
          lines: lines.map((line) => {
            'id': line.id,
            'category': line.category.name,
            'name': line.name,
            'description': line.description,
            'amountPlanned': line.amountPlanned,
            'amountRealized': line.amountRealized,
            'notes': line.notes,
          }).toList(),
        ),
        shouldRetry: (error) => _isRetryableError(error),
      );
      return Right(budget);
    } on ForbiddenException catch (e) {
      return Left(ForbiddenFailure(e.message));
    } on UnauthorizedException {
      return Left(UnauthorizedFailure('Session expirée'));
    } on ServerException catch (e) {
      return Left(ServerFailure(e.message));
    } on TimeoutException {
      return Left(NetworkFailure('Délai d\'attente dépassé'));
    } catch (e) {
      return Left(UnexpectedFailure('Erreur inattendue: $e'));
    }
  }

  @override
  Future<Either<Failure, Map<String, dynamic>>> getBudgetTracking({
    required String budgetId,
  }) async {
    if (!await networkInfo.isConnected) {
      return Left(NetworkFailure('Pas de connexion Internet'));
    }

    try {
      final tracking = await _retryPolicy.execute(
        operation: () => remoteDatasource.getBudgetTracking(budgetId: budgetId),
        shouldRetry: (error) => _isRetryableError(error),
      );
      return Right(tracking);
    } on UnauthorizedException {
      return Left(UnauthorizedFailure('Session expirée'));
    } on ServerException catch (e) {
      return Left(ServerFailure(e.message));
    } on TimeoutException {
      return Left(NetworkFailure('Délai d\'attente dépassé'));
    } catch (e) {
      return Left(UnexpectedFailure('Erreur inattendue: $e'));
    }
  }

  /// Determine if an error is retryable
  bool _isRetryableError(dynamic error) {
    // Server errors are retryable
    if (error is ServerException) return true;

    // Timeout errors are retryable
    if (error is TimeoutException) return true;

    // Client errors are not retryable
    if (error is UnauthorizedException) return false;
    if (error is ForbiddenException) return false;
    if (error is NotFoundException) return false;
    if (error is ValidationException) return false;

    // Unknown errors - default to not retryable
    return false;
  }

  // === MÉTHODES NON IMPLÉMENTÉES (Stubs) ===

  @override
  Future<Either<Failure, TransactionApproval>> requestApproval({
    required String transactionId,
    required TransactionType transactionType,
    required double amount,
  }) async {
    return Left(
        NotImplementedFailure('Fonctionnalité en cours de développement'));
  }

  @override
  Future<Either<Failure, List<TransactionApproval>>> getApprovalsHistory({
    String? organizationId,
    DateTime? startDate,
    DateTime? endDate,
    ApprovalStatus? status,
  }) async {
    return Left(
        NotImplementedFailure('Fonctionnalité en cours de développement'));
  }

  @override
  Future<Either<Failure, Budget>> updateBudget({
    required String budgetId,
    String? name,
    String? description,
    List<BudgetLine>? lines,
    BudgetStatus? status,
  }) async {
    return Left(
        NotImplementedFailure('Fonctionnalité en cours de développement'));
  }

  @override
  Future<Either<Failure, void>> deleteBudget(String budgetId) async {
    return Left(
        NotImplementedFailure('Fonctionnalité en cours de développement'));
  }

  @override
  Future<Either<Failure, List<FinancialAuditLog>>> getAuditLogs({
    String? organizationId,
    DateTime? startDate,
    DateTime? endDate,
    AuditOperation? operation,
    AuditEntityType? entityType,
    AuditSeverity? severity,
    int? limit,
  }) async {
    return Left(
        NotImplementedFailure('Fonctionnalité en cours de développement'));
  }

  @override
  Future<Either<Failure, List<FinancialAuditLog>>> getAnomalies({
    String? organizationId,
    DateTime? startDate,
    DateTime? endDate,
  }) async {
    return Left(
        NotImplementedFailure('Fonctionnalité en cours de développement'));
  }

  @override
  Future<Either<Failure, String>> exportAuditLogs({
    required String organizationId,
    DateTime? startDate,
    DateTime? endDate,
    String format = 'csv',
  }) async {
    return Left(
        NotImplementedFailure('Fonctionnalité en cours de développement'));
  }

  @override
  Future<Either<Failure, Map<String, dynamic>>> getWorkflowStats({
    required String organizationId,
    DateTime? startDate,
    DateTime? endDate,
  }) async {
    return Left(
        NotImplementedFailure('Fonctionnalité en cours de développement'));
  }
}
