using CMSMicroservice.Application.Common.Exceptions;
using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Application.Common.Models;
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.PurchasePackage;

public class PurchasePackageCommandHandler 
    : IRequestHandler<PurchasePackageCommand, PaymentInitiateResult>
{
    private readonly IApplicationDbContext _context;
    private readonly IPaymentGatewayService _paymentGateway;
    private readonly ILogger<PurchasePackageCommandHandler> _logger;

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

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

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

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

            // 2. بررسی اینکه قبلاً پکیج نخریده باشد
            if (user.PackagePurchaseMethod != PackagePurchaseMethod.None)
            {
                _logger.LogWarning(
                    "User {UserId} has already purchased package via {Method}", 
                    request.UserId, 
                    user.PackagePurchaseMethod
                );
                throw new ValidationException(
                    "شما قبلاً پکیج را خریداری کرده‌اید"
                );
            }

            // 3. پیدا کردن پکیج (فعلاً پکیج طلایی)
            var goldenPackage = await _context.Packages
                .FirstOrDefaultAsync(
                    p => p.Title.Contains("طلایی") || p.Title.Contains("Golden"), 
                    cancellationToken
                );

            if (goldenPackage == null)
            {
                _logger.LogError("Package not found in database");
                throw new NotFoundException("پکیج یافت نشد");
            }

            // 4. پیدا کردن آدرس پیش‌فرض کاربر (برای فیلد اجباری)
            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}", request.UserId);
                throw new ValidationException(
                    "لطفاً ابتدا یک آدرس برای خود ثبت کنید"
                );
            }

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

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

            _logger.LogInformation(
                "Created 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 ?? "",
                CallbackUrl = $"https://yourdomain.com/api/package/verify-package",
                Description = $"خرید پکیج - سفارش #{order.Id}"
            };

            var paymentResult = await _paymentGateway.InitiatePaymentAsync(paymentRequest);

            if (!paymentResult.IsSuccess)
            {
                _logger.LogError(
                    "Payment gateway failed for OrderId {OrderId}: {ErrorMessage}", 
                    order.Id, 
                    paymentResult.ErrorMessage
                );
                
                // به‌روزرسانی وضعیت سفارش
                order.PaymentStatus = PaymentStatus.Reject;
                await _context.SaveChangesAsync(cancellationToken);
                
                throw new Exception(
                    $"خطا در ارتباط با درگاه پرداخت: {paymentResult.ErrorMessage}"
                );
            }

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

            return paymentResult;
        }
        catch (Exception ex)
        {
            _logger.LogError(
                ex, 
                "Error in PurchasePackageCommand for UserId: {UserId}", 
                request.UserId
            );
            throw;
        }
    }
}
