import 'package:dio/dio.dart';
import 'package:flux_localization/flux_localization.dart';
import 'package:inspireui/utils/logs.dart';

import '../../models/entities/paging_response.dart';
import '../../models/entities/rating_count.dart';
import '../../models/entities/review.dart';
import '../../models/entities/review_payload.dart';
import '../../services/review_service.dart';
import 'judge_extension.dart';

class _JudgeEndpoints {
  static const String reviews = '/reviews';
  static const String productRatingCount = '/reviews/count';
  static const String product = '/products/-1';
}

class JudgeReviewService extends ReviewService {
  JudgeReviewService({required this.apiKey, required this.domain})
    : _dio = Dio(
        BaseOptions(
          baseUrl: _judgeApiDomain,
          headers: {'Content-Type': 'application/json'},
        ),
      ) {
    _setupInterceptors();
  }

  final String apiKey;
  final String domain; // Shop domain for Judge.me
  final Dio _dio;

  static const String _judgeApiDomain = 'https://judge.me/api/v1';

  void _setupInterceptors() {
    _dio.interceptors.add(
      InterceptorsWrapper(
        onRequest: (options, handler) {
          options.queryParameters.addAll({
            'api_token': apiKey,
            'shop_domain': domain,
          });
          return handler.next(options);
        },
      ),
    );
  }

  @override
  Future<void> createReview(ReviewPayload payload) async {
    try {
      await _dio.post(_JudgeEndpoints.reviews, data: payload.toJudgeJson());
    } catch (e) {
      printLog(e);
      throw S.current.failedToCreateReview;
    }
    return;
  }

  @override
  Future<PagingResponse<Review>> getReviews(
    String productId, {
    int page = 1,
    int perPage = 20,
  }) async {
    try {
      final internalProductId = await _getJudgeProductId(
        externalProductId: productId,
      );
      if (internalProductId == null) {
        return const PagingResponse();
      }

      printLog('[JudgeReview] getReviews $internalProductId');

      final response = await _dio.get(
        _JudgeEndpoints.reviews,
        queryParameters: {
          'product_id': internalProductId,
          'page': page,
          'per_page': perPage,
          'published': true,
        },
      );
      final data = response.data;
      if (data is Map) {
        final reviews = data['reviews'];
        if (reviews is List) {
          return PagingResponse(
            data: reviews.map((e) => ReviewParser.fromJudge(e)).toList(),
          );
        }
      }
    } catch (e) {
      printLog(e);
    }
    return const PagingResponse();
  }

  Future<String?> _getJudgeProductId({
    required String externalProductId,
  }) async {
    try {
      final response = await _dio.get(
        _JudgeEndpoints.product,
        queryParameters: {'external_id': externalProductId.numberOfProductId},
      );

      final data = response.data;
      if (data is Map) {
        final productId = data['product']['id'];
        if (productId is int) {
          return productId.toString();
        }
      }
    } catch (e) {
      printLog(e);
    }
    return null;
  }

  @override
  Future<RatingCount?> getProductRatingCount(String productId) async {
    final internalProductId = await _getJudgeProductId(
      externalProductId: productId,
    );
    if (internalProductId == null) {
      return null;
    }

    final ratingCount = await Future.wait([
      _getRatingCountOfProduct(internalProductId, 1),
      _getRatingCountOfProduct(internalProductId, 2),
      _getRatingCountOfProduct(internalProductId, 3),
      _getRatingCountOfProduct(internalProductId, 4),
      _getRatingCountOfProduct(internalProductId, 5),
    ]);
    return RatingCount(
      oneStar: ratingCount[0],
      twoStar: ratingCount[1],
      threeStar: ratingCount[2],
      fourStar: ratingCount[3],
      fiveStar: ratingCount[4],
    );
  }

  Future<int> _getRatingCountOfProduct(
    String internalProductId,
    int rating,
  ) async {
    try {
      final response = await _dio.get(
        _JudgeEndpoints.productRatingCount,
        queryParameters: {
          'product_id': internalProductId,
          'rating': rating,
          'published': true,
        },
      );
      final data = response.data;
      if (data is Map) {
        final count = data['count'];
        if (count is int) {
          return count;
        }
      }
    } catch (e) {
      printLog(e);
    }
    return 0;
  }

  @override
  Future<PagingResponse<Review>> getListReviewByUserEmail(
    String email, {
    int page = 1,
    int perPage = 20,
    String? status,
  }) async {
    return const PagingResponse();
  }
}
