import 'package:dartz/dartz.dart';
import 'package:injectable/injectable.dart';
import '../../../../../core/errors/failures.dart';
import '../../../../../core/errors/exceptions.dart';
import '../../../../../core/network/network_info.dart';
import '../../domain/entities/p2p_trade_entity.dart';
import '../../domain/entities/p2p_dispute_entity.dart';
import '../../domain/entities/p2p_review_entity.dart';
import '../../domain/repositories/p2p_trades_repository.dart';
import '../../domain/usecases/trades/get_trades_usecase.dart';
import '../datasources/p2p_remote_datasource.dart';
import '../datasources/p2p_local_datasource.dart';
import '../models/p2p_trade_model.dart';

@Injectable(as: P2PTradesRepository)
class P2PTradesRepositoryImpl implements P2PTradesRepository {
  final P2PRemoteDataSource _remoteDataSource;
  final P2PLocalDataSource _localDataSource;
  final NetworkInfo _networkInfo;

  const P2PTradesRepositoryImpl(
    this._remoteDataSource,
    this._localDataSource,
    this._networkInfo,
  );

  @override
  Future<Either<Failure, P2PTradesResponse>> getTrades({
    String? status,
    int? limit,
    int? offset,
    String? sortBy,
    String? sortDirection,
    bool includeStats = true,
    bool includeActivity = true,
    DateTime? dateFrom,
    DateTime? dateTo,
  }) async {
    try {
      if (await _networkInfo.isConnected) {
        final result = await _remoteDataSource.getTrades(
          status: status,
          type: null,
          page: offset != null ? (offset / (limit ?? 10)).floor() + 1 : 1,
          perPage: limit ?? 10,
        );

        // Cache the result
        await _localDataSource.cacheTradesList(result);

        // Convert to P2PTradesResponse
        final trades = (result['data'] as List?)
                ?.map((json) => P2PTradeModel.fromJson(json).toEntity())
                .toList() ??
            [];

        // For now, return a basic response structure
        return Right(P2PTradesResponse(
          tradeStats: P2PTradeStats(
            activeCount: result['stats']?['activeCount'] ?? 0,
            completedCount: result['stats']?['completedCount'] ?? 0,
            totalVolume:
                (result['stats']?['totalVolume'] as num?)?.toDouble() ?? 0.0,
            avgCompletionTime:
                result['stats']?['avgCompletionTime']?.toString(),
            successRate: result['stats']?['successRate'] ?? 0,
          ),
          recentActivity: [], // TODO: Implement activity logs
          activeTrades: trades.where((t) => t.status == 'IN_PROGRESS').toList(),
          pendingTrades: trades.where((t) => t.status == 'PENDING').toList(),
          completedTrades:
              trades.where((t) => t.status == 'COMPLETED').toList(),
          disputedTrades: trades.where((t) => t.status == 'DISPUTED').toList(),
        ));
      } else {
        // Try to get cached data
        final cachedData = await _localDataSource.getCachedTradesList();
        if (cachedData != null) {
          final trades = (cachedData['data'] as List?)
                  ?.map((json) => P2PTradeModel.fromJson(json).toEntity())
                  .toList() ??
              [];

          return Right(P2PTradesResponse(
            tradeStats: P2PTradeStats(
              activeCount: cachedData['stats']?['activeCount'] ?? 0,
              completedCount: cachedData['stats']?['completedCount'] ?? 0,
              totalVolume:
                  (cachedData['stats']?['totalVolume'] as num?)?.toDouble() ??
                      0.0,
              avgCompletionTime:
                  cachedData['stats']?['avgCompletionTime']?.toString(),
              successRate: cachedData['stats']?['successRate'] ?? 0,
            ),
            recentActivity: [], // TODO: Implement activity logs
            activeTrades:
                trades.where((t) => t.status == 'IN_PROGRESS').toList(),
            pendingTrades: trades.where((t) => t.status == 'PENDING').toList(),
            completedTrades:
                trades.where((t) => t.status == 'COMPLETED').toList(),
            disputedTrades:
                trades.where((t) => t.status == 'DISPUTED').toList(),
          ));
        }
        return Left(NetworkFailure('No internet connection'));
      }
    } catch (e) {
      // Try cached data on error
      try {
        final cachedData = await _localDataSource.getCachedTradesList();
        if (cachedData != null) {
          final trades = (cachedData['data'] as List?)
                  ?.map((json) => P2PTradeModel.fromJson(json).toEntity())
                  .toList() ??
              [];

          return Right(P2PTradesResponse(
            tradeStats: P2PTradeStats(
              activeCount: cachedData['stats']?['activeCount'] ?? 0,
              completedCount: cachedData['stats']?['completedCount'] ?? 0,
              totalVolume:
                  (cachedData['stats']?['totalVolume'] as num?)?.toDouble() ??
                      0.0,
              avgCompletionTime:
                  cachedData['stats']?['avgCompletionTime']?.toString(),
              successRate: cachedData['stats']?['successRate'] ?? 0,
            ),
            recentActivity: [], // TODO: Implement activity logs
            activeTrades:
                trades.where((t) => t.status == 'IN_PROGRESS').toList(),
            pendingTrades: trades.where((t) => t.status == 'PENDING').toList(),
            completedTrades:
                trades.where((t) => t.status == 'COMPLETED').toList(),
            disputedTrades:
                trades.where((t) => t.status == 'DISPUTED').toList(),
          ));
        }
      } catch (_) {}

      return Left(ServerFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, P2PTradeEntity>> getTradeById(
    String tradeId, {
    bool includeCounterparty = true,
    bool includeDispute = true,
    bool includeTimeline = true,
  }) async {
    if (!await _networkInfo.isConnected) {
      return Left(NetworkFailure('No internet connection'));
    }

    try {
      final result = await _remoteDataSource.getTradeById(tradeId);
      final trade = P2PTradeModel.fromJson(result).toEntity();

      // Cache the trade
      await _localDataSource.cacheTrade(trade);

      return Right(trade);
    } catch (e) {
      // Try cached data on error
      try {
        final cachedTrade = await _localDataSource.getCachedTrade(tradeId);
        if (cachedTrade != null) {
          return Right(P2PTradeModel.fromJson(cachedTrade).toEntity());
        }
      } catch (_) {}

      return Left(ServerFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, P2PTradeEntity>> initiateTrade({
    required String offerId,
    required double amount,
    double? fiatAmount,
    required String paymentMethodId,
    String? message,
    int? autoAcceptTime,
  }) async {
    if (!await _networkInfo.isConnected) {
      return Left(NetworkFailure('No internet connection'));
    }

    try {
      final tradeData = {
        'offerId': offerId,
        'amount': amount,
        if (fiatAmount != null) 'fiatAmount': fiatAmount,
        'paymentMethodId': paymentMethodId,
        if (message != null) 'message': message,
        if (autoAcceptTime != null) 'autoAcceptTime': autoAcceptTime,
      };

      final result = await _remoteDataSource.createTrade(
        offerId: offerId,
        amount: amount,
        paymentMethodId: paymentMethodId,
        notes: message,
      );
      final trade = result.toEntity();

      // Cache the new trade
      await _localDataSource.cacheTrade(trade);

      // Invalidate trades list cache
      await _localDataSource.clearTradesListCache();

      return Right(trade);
    } catch (e) {
      return Left(ServerFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, void>> confirmTrade({
    required String tradeId,
    String? paymentReference,
    String? paymentProof,
    String? notes,
  }) async {
    if (!await _networkInfo.isConnected) {
      return Left(NetworkFailure('No internet connection'));
    }

    try {
      await _remoteDataSource.confirmTrade(tradeId);
      return const Right(null);
    } catch (e) {
      return Left(ServerFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, void>> cancelTrade({
    required String tradeId,
    required String reason,
    bool forceCancel = false,
  }) async {
    if (!await _networkInfo.isConnected) {
      return Left(NetworkFailure('No internet connection'));
    }

    try {
      await _remoteDataSource.cancelTrade(tradeId, reason);
      return const Right(null);
    } catch (e) {
      return Left(ServerFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, P2PDisputeEntity>> disputeTrade({
    required String tradeId,
    required String reason,
    required String description,
    List<String>? evidence,
    String? priority,
  }) async {
    if (!await _networkInfo.isConnected) {
      return Left(NetworkFailure('No internet connection'));
    }

    try {
      await _remoteDataSource.disputeTrade(tradeId, reason, description);
      // Convert to P2PDisputeEntity - you'll need to create this model
      return Left(ServerFailure('Dispute entity conversion not implemented'));
    } catch (e) {
      return Left(ServerFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, void>> releaseEscrow({
    required String tradeId,
    String? releaseReason,
    bool partialRelease = false,
    double? releaseAmount,
  }) async {
    if (!await _networkInfo.isConnected) {
      return Left(NetworkFailure('No internet connection'));
    }

    try {
      await _remoteDataSource.releaseTrade(tradeId);
      return const Right(null);
    } catch (e) {
      return Left(ServerFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, P2PReviewEntity>> reviewTrade({
    required String tradeId,
    required int communicationRating,
    required int speedRating,
    required int trustRating,
    required String comment,
    bool? isPositive,
  }) async {
    if (!await _networkInfo.isConnected) {
      return Left(NetworkFailure('No internet connection'));
    }

    try {
      final reviewData = {
        'communicationRating': communicationRating,
        'speedRating': speedRating,
        'trustRating': trustRating,
        'comment': comment,
        if (isPositive != null) 'isPositive': isPositive,
      };

      final result = await _remoteDataSource.reviewTrade(tradeId, reviewData);
      // Convert to P2PReviewEntity - you'll need to create this model
      return Left(ServerFailure('Review entity conversion not implemented'));
    } catch (e) {
      return Left(ServerFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, List<Map<String, dynamic>>>> getTradeMessages(
    String tradeId,
  ) async {
    if (!await _networkInfo.isConnected) {
      return Left(NetworkFailure('No internet connection'));
    }

    try {
      // This would need to be implemented in the remote data source
      return Left(ServerFailure('Trade messages not implemented'));
    } catch (e) {
      return Left(ServerFailure(e.toString()));
    }
  }

  @override
  Future<Either<Failure, void>> sendTradeMessage({
    required String tradeId,
    required String message,
  }) async {
    if (!await _networkInfo.isConnected) {
      return Left(NetworkFailure('No internet connection'));
    }

    try {
      // This would need to be implemented in the remote data source
      return const Right(null);
    } catch (e) {
      return Left(ServerFailure(e.toString()));
    }
  }
}
