using CMSMicroservice.Application.Common.Exceptions;
using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Domain.Entities;
using CMSMicroservice.Domain.Enums;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using ValidationException = FluentValidation.ValidationException;

namespace CMSMicroservice.Application.PackageCQ.Commands.PurchaseGoldenPackage;

public class PurchaseGoldenPackageCommandHandler : IRequestHandler<PurchaseGoldenPackageCommand, PurchaseGoldenPackageResponseDto>
{
    private readonly IApplicationDbContext _context;
    private readonly IPaymentGatewayService _paymentGateway;
    private readonly ILogger<PurchaseGoldenPackageCommandHandler> _logger;

    public PurchaseGoldenPackageCommandHandler(
        IApplicationDbContext context,
        IPaymentGatewayService paymentGateway,
        ILogger<PurchaseGoldenPackageCommandHandler> logger)
    {
        _context = context;
        _paymentGateway = paymentGateway;
        _logger = logger;
    }

    public async Task<PurchaseGoldenPackageResponseDto> Handle(PurchaseGoldenPackageCommand request, CancellationToken cancellationToken)
    {
        try
        {
            _logger.LogInformation(
                "Starting golden package purchase for UserId: {UserId}, PackageId: {PackageId}",
                request.UserId,
                request.PackageId);

            // 1. پیدا کردن کاربر
            var user = await _context.Users
                .FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken);

            if (user == null)
            {
                _logger.LogWarning("User not found for golden package purchase. UserId: {UserId}", request.UserId);
                throw new NotFoundException(nameof(User), request.UserId);
            }

            // 2. جلوگیری از خرید مجدد پکیج طلایی
            if (user.PackagePurchaseMethod != PackagePurchaseMethod.None)
            {
                _logger.LogWarning(
                    "User {UserId} has already purchased golden package via {Method}",
                    request.UserId,
                    user.PackagePurchaseMethod);

                throw new ValidationException("شما قبلاً پکیج طلایی را خریداری کرده‌اید.");
            }

            // 3. پیدا کردن پکیج
            var package = await _context.Packages
                .FirstOrDefaultAsync(p => p.Id == request.PackageId, cancellationToken);

            if (package == null)
            {
                _logger.LogWarning("Golden package not found. PackageId: {PackageId}", request.PackageId);
                throw new NotFoundException(nameof(Package), request.PackageId);
            }

            // اطمینان از اینکه این همان پکیج طلایی است
            if (!package.Title.Contains("طلایی", StringComparison.OrdinalIgnoreCase) &&
                !package.Title.Contains("golden", StringComparison.OrdinalIgnoreCase))
            {
                _logger.LogWarning(
                    "PackageId {PackageId} is not a golden package. Title: {Title}",
                    request.PackageId,
                    package.Title);

                throw new ValidationException("فقط پکیج طلایی قابل خرید است.");
            }

            // 4. پیدا کردن آدرس پیش‌فرض کاربر (الزامی برای UserOrder)
            var defaultAddress = await _context.UserAddresses
                .Where(a => a.UserId == request.UserId)
                .OrderByDescending(a => a.Created)
                .FirstOrDefaultAsync(cancellationToken);

            if (defaultAddress == null)
            {
                _logger.LogWarning("No address found for user {UserId} in golden package purchase", request.UserId);
                throw new ValidationException("لطفاً ابتدا یک آدرس برای خود ثبت کنید.");
            }

            // 5. ایجاد سفارش
            var order = new UserOrder
            {
                UserId = user.Id,
                PackageId = package.Id,
                Amount = package.Price,
                PaymentStatus = PaymentStatus.Pending,
                DeliveryStatus = DeliveryStatus.None,
                UserAddressId = defaultAddress.Id,
                PaymentMethod = PaymentMethod.IPG
            };

            _context.UserOrders.Add(order);
            await _context.SaveChangesAsync(cancellationToken);

            _logger.LogInformation(
                "Created golden package UserOrder {OrderId} for UserId {UserId}, Amount: {Amount}",
                order.Id,
                request.UserId,
                order.Amount);

            // 6. شروع پرداخت با درگاه
            var paymentRequest = new PaymentRequest
            {
                Amount = order.Amount,
                UserId = user.Id,
                Mobile = user.Mobile ?? string.Empty,
                CallbackUrl = request.ReturnUrl,
                Description = $"خرید پکیج طلایی - سفارش #{order.Id}"
            };

            var paymentResult = await _paymentGateway.InitiatePaymentAsync(paymentRequest, cancellationToken);

            if (!paymentResult.IsSuccess)
            {
                _logger.LogError(
                    "Payment gateway initiation failed for golden package. OrderId {OrderId}: {ErrorMessage}",
                    order.Id,
                    paymentResult.ErrorMessage);

                order.PaymentStatus = PaymentStatus.Reject;
                await _context.SaveChangesAsync(cancellationToken);

                throw new Exception($"خطا در ارتباط با درگاه پرداخت: {paymentResult.ErrorMessage}");
            }

            _logger.LogInformation(
                "Golden package payment initiated successfully. OrderId: {OrderId}, RefId: {RefId}",
                order.Id,
                paymentResult.RefId);

            return new PurchaseGoldenPackageResponseDto
            {
                Success = true,
                Message = "لطفاً به درگاه پرداخت منتقل شوید.",
                OrderId = order.Id,
                PaymentGatewayUrl = paymentResult.GatewayUrl ?? string.Empty,
                TrackingCode = paymentResult.RefId ?? string.Empty
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(
                ex,
                "Error in PurchaseGoldenPackageCommand for UserId: {UserId}",
                request.UserId);
            throw;
        }
    }
}
