import 'package:injectable/injectable.dart';
import 'package:dio/dio.dart';
import 'package:mobile/core/network/dio_client.dart';
import 'package:mobile/core/errors/exceptions.dart';
import 'package:mobile/core/constants/api_constants.dart';
import '../models/staking_pool_model.dart';
import '../models/staking_position_model.dart';
import '../models/staking_stats_model.dart';
import '../models/pool_analytics_model.dart';

@injectable
class StakingRemoteDataSource {
  final DioClient _client;
  const StakingRemoteDataSource(this._client);

  /// Fetch all staking pools
  Future<List<StakingPoolModel>> getPools({
    String? status,
    double? minApr,
    double? maxApr,
    String? token,
  }) async {
    print(
        '🏊 STAKING_REMOTE_DS: getPools() called - status=$status, minApr=$minApr, maxApr=$maxApr, token=$token');
    try {
      final queryParams = <String, dynamic>{};
      if (status != null) queryParams['status'] = status;
      if (minApr != null) queryParams['minApr'] = minApr.toString();
      if (maxApr != null) queryParams['maxApr'] = maxApr.toString();
      if (token != null) queryParams['token'] = token;

      final response = await _client.get(
        ApiConstants.stakingPools,
        queryParameters: queryParams,
      );

      if (response.statusCode == 200) {
        print('🏊 STAKING_REMOTE_DS: getPools() success');
        final data = response.data as List;
        return data
            .map((e) => StakingPoolModel.fromJson(e as Map<String, dynamic>))
            .toList();
      } else {
        throw ServerException(
            'Failed to fetch staking pools: ${response.statusCode}');
      }
    } on DioException catch (e) {
      print('🏊 STAKING_REMOTE_DS: getPools() DioException: ${e.type}');
      if (e.type == DioExceptionType.connectionTimeout ||
          e.type == DioExceptionType.receiveTimeout) {
        throw const TimeoutException('Connection timeout');
      }
      throw NetworkException(e.message ?? 'Network error');
    } catch (e) {
      print('🏊 STAKING_REMOTE_DS: getPools() Exception: $e');
      throw ServerException(e.toString());
    }
  }

  /// Fetch user's staking positions
  Future<List<StakingPositionModel>> getUserPositions({
    String? poolId,
    String? status,
  }) async {
    print(
        '👤 STAKING_REMOTE_DS: getUserPositions() called - poolId=$poolId, status=$status');
    try {
      final params = <String, dynamic>{};
      if (status != null) params['status'] = status;
      if (poolId != null) params['poolId'] = poolId;

      final response = await _client.get(
        ApiConstants.stakingPositions,
        queryParameters: params,
      );
      if (response.statusCode == 200) {
        print('👤 STAKING_REMOTE_DS: getUserPositions() success');
        final data = response.data as List;
        return data
            .map(
                (e) => StakingPositionModel.fromJson(e as Map<String, dynamic>))
            .toList();
      } else {
        throw ServerException(
            'Failed to fetch positions: ${response.statusCode}');
      }
    } on DioException catch (e) {
      print('👤 STAKING_REMOTE_DS: getUserPositions() DioException: ${e.type}');
      if (e.type == DioExceptionType.connectionTimeout ||
          e.type == DioExceptionType.receiveTimeout) {
        throw const TimeoutException('Connection timeout');
      }
      throw NetworkException(e.message ?? 'Network error');
    } catch (e) {
      print('👤 STAKING_REMOTE_DS: getUserPositions() Exception: $e');
      throw ServerException(e.toString());
    }
  }

  /// Stake into a pool
  Future<StakingPositionModel> stake({
    required String poolId,
    required double amount,
  }) async {
    try {
      final body = {'poolId': poolId, 'amount': amount};
      final response = await _client.post(
        ApiConstants.stakingPositions,
        data: body,
      );
      if (response.statusCode == 200) {
        return StakingPositionModel.fromJson(
            response.data as Map<String, dynamic>);
      }
      throw ServerException('Failed to stake: ${response.statusCode}');
    } on DioException catch (e) {
      if (e.type == DioExceptionType.connectionTimeout ||
          e.type == DioExceptionType.receiveTimeout) {
        throw const TimeoutException('Connection timeout');
      }
      throw NetworkException(e.message ?? 'Network error');
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  /// Withdraw a staking position
  Future<StakingPositionModel> withdraw(String positionId) async {
    try {
      final url = '${ApiConstants.stakingWithdraw}/$positionId/withdraw';
      final response = await _client.post(url);
      if (response.statusCode == 200) {
        return StakingPositionModel.fromJson(
            response.data as Map<String, dynamic>);
      }
      throw ServerException('Failed to withdraw: ${response.statusCode}');
    } on DioException catch (e) {
      if (e.type == DioExceptionType.connectionTimeout ||
          e.type == DioExceptionType.receiveTimeout) {
        throw const TimeoutException('Connection timeout');
      }
      throw NetworkException(e.message ?? 'Network error');
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  /// Claim rewards for a position
  Future<StakingPositionModel> claimRewards(String positionId) async {
    try {
      final url = '${ApiConstants.stakingClaim}/$positionId/claim';
      final response = await _client.post(url);
      if (response.statusCode == 200) {
        return StakingPositionModel.fromJson(
            response.data as Map<String, dynamic>);
      }
      throw ServerException('Failed to claim rewards: ${response.statusCode}');
    } on DioException catch (e) {
      if (e.type == DioExceptionType.connectionTimeout ||
          e.type == DioExceptionType.receiveTimeout) {
        throw const TimeoutException('Connection timeout');
      }
      throw NetworkException(e.message ?? 'Network error');
    } catch (e) {
      throw ServerException(e.toString());
    }
  }

  /// Fetch overall staking statistics
  Future<StakingStatsModel> getStats() async {
    print('📊 STAKING_REMOTE_DS: getStats() called');
    try {
      final response = await _client.get(ApiConstants.stakingStats);
      if (response.statusCode == 200) {
        print('📊 STAKING_REMOTE_DS: getStats() success');
        return StakingStatsModel.fromJson(
            response.data as Map<String, dynamic>);
      }
      throw ServerException(
          'Failed to fetch staking stats: ${response.statusCode}');
    } on DioException catch (e) {
      print('📊 STAKING_REMOTE_DS: getStats() DioException: ${e.type}');
      if (e.type == DioExceptionType.connectionTimeout ||
          e.type == DioExceptionType.receiveTimeout) {
        throw const TimeoutException('Connection timeout');
      }
      throw NetworkException(e.message ?? 'Network error');
    } catch (e) {
      print('📊 STAKING_REMOTE_DS: getStats() Exception: $e');
      throw ServerException(e.toString());
    }
  }

  /// Fetch pool analytics for a specific pool
  Future<PoolAnalyticsModel> getPoolAnalytics(
    String poolId, {
    String? timeframe,
  }) async {
    try {
      final params = <String, dynamic>{};
      if (timeframe != null) params['timeframe'] = timeframe;
      final url = '${ApiConstants.stakingPoolAnalytics}/$poolId/analytics';
      final response = await _client.get(url, queryParameters: params);
      if (response.statusCode == 200) {
        final data = (response.data as Map<String, dynamic>)['analytics']
            as Map<String, dynamic>;
        return PoolAnalyticsModel.fromJson(data);
      }
      throw ServerException(
          'Failed to fetch pool analytics: ${response.statusCode}');
    } on DioException catch (e) {
      if (e.type == DioExceptionType.connectionTimeout ||
          e.type == DioExceptionType.receiveTimeout) {
        throw const TimeoutException('Connection timeout');
      }
      throw NetworkException(e.message ?? 'Network error');
    } catch (e) {
      throw ServerException(e.toString());
    }
  }
}
