package com.ycwl.basic.pricing.service.impl;

import com.ycwl.basic.pricing.dto.*;
import com.ycwl.basic.pricing.enums.VoucherDiscountType;
import com.ycwl.basic.pricing.service.IDiscountProvider;
import com.ycwl.basic.pricing.service.IVoucherService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * 券码折扣提供者
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class VoucherDiscountProvider implements IDiscountProvider {
    
    private final IVoucherService voucherService;
    
    @Override
    public String getProviderType() {
        return "VOUCHER";
    }
    
    @Override
    public int getPriority() {
        return 100; // 券码优先级最高
    }
    
    @Override
    public List<DiscountInfo> detectAvailableDiscounts(DiscountDetectionContext context) {
        List<DiscountInfo> discounts = new ArrayList<>();
        
        if (context.getFaceId() == null || context.getScenicId() == null) {
            return discounts;
        }
        
        try {
            VoucherInfo voucherInfo = null;
            
            // 优先检查用户主动输入的券码
            if (StringUtils.hasText(context.getVoucherCode())) {
                voucherInfo = voucherService.validateAndGetVoucherInfo(
                    context.getVoucherCode(), 
                    context.getFaceId(), 
                    context.getScenicId()
                );
            } 
            // 如果没有输入券码且允许自动使用，则查找最优券码
            else if (Boolean.TRUE.equals(context.getAutoUseVoucher())) {
                voucherInfo = voucherService.getBestVoucher(
                    context.getFaceId(), 
                    context.getScenicId(), 
                    context
                );
            }
            
            if (voucherInfo != null && Boolean.TRUE.equals(voucherInfo.getAvailable())) {
                // 计算券码优惠金额
                BigDecimal discountAmount = voucherService.calculateVoucherDiscount(voucherInfo, context);
                
                if (discountAmount.compareTo(BigDecimal.ZERO) > 0) {
                    DiscountInfo discountInfo = new DiscountInfo();
                    discountInfo.setDiscountId(voucherInfo.getVoucherId());
                    discountInfo.setDiscountType("VOUCHER");
                    discountInfo.setDiscountName("券码优惠");
                    discountInfo.setDiscountDescription(buildDiscountDescription(voucherInfo));
                    discountInfo.setDiscountAmount(discountAmount);
                    discountInfo.setProviderType(getProviderType());
                    discountInfo.setPriority(getPriority());
                    discountInfo.setStackable(isStackable(voucherInfo)); // 只有全场免费不可叠加
                    discountInfo.setVoucherCode(voucherInfo.getVoucherCode());
                    
                    discounts.add(discountInfo);
                }
            }
        } catch (Exception e) {
            log.warn("检测券码优惠时发生异常", e);
        }
        
        return discounts;
    }
    
    @Override
    public DiscountResult applyDiscount(DiscountInfo discountInfo, DiscountDetectionContext context) {
        DiscountResult result = new DiscountResult();
        result.setDiscountInfo(discountInfo);
        
        try {
            String voucherCode = discountInfo.getVoucherCode();
            if (!StringUtils.hasText(voucherCode)) {
                result.setSuccess(false);
                result.setFailureReason("券码信息丢失");
                return result;
            }
            
            // 重新验证券码
            VoucherInfo voucherInfo = voucherService.validateAndGetVoucherInfo(
                voucherCode, 
                context.getFaceId(), 
                context.getScenicId()
            );
            
            if (voucherInfo == null || !Boolean.TRUE.equals(voucherInfo.getAvailable())) {
                result.setSuccess(false);
                result.setFailureReason("券码无效或不可用");
                return result;
            }
            
            // 计算实际优惠金额
            BigDecimal actualDiscount = voucherService.calculateVoucherDiscount(voucherInfo, context);
            BigDecimal finalAmount;
            
            // 对于全场免费券码，最终金额为0
            if (voucherInfo.getDiscountType() == VoucherDiscountType.FREE_ALL) {
                finalAmount = BigDecimal.ZERO;
                actualDiscount = context.getCurrentAmount();
            } else {
                finalAmount = context.getCurrentAmount().subtract(actualDiscount);
                if (finalAmount.compareTo(BigDecimal.ZERO) < 0) {
                    finalAmount = BigDecimal.ZERO;
                    actualDiscount = context.getCurrentAmount();
                }
            }
            
            result.setActualDiscountAmount(actualDiscount);
            result.setFinalAmount(finalAmount);
            result.setSuccess(true);
            
            log.info("成功应用券码: {}, 优惠金额: {}", voucherCode, actualDiscount);
            
        } catch (Exception e) {
            log.error("应用券码失败: " + discountInfo.getVoucherCode(), e);
            result.setSuccess(false);
            result.setFailureReason("券码应用失败: " + e.getMessage());
        }
        
        return result;
    }
    
    @Override
    public boolean canApply(DiscountInfo discountInfo, DiscountDetectionContext context) {
        return "VOUCHER".equals(discountInfo.getDiscountType()) &&
               context.getFaceId() != null &&
               context.getScenicId() != null &&
               StringUtils.hasText(discountInfo.getVoucherCode());
    }
    
    /**
     * 构建优惠描述
     */
    private String buildDiscountDescription(VoucherInfo voucherInfo) {
        if (voucherInfo.getDiscountType() == null) {
            return "券码优惠";
        }
        
        return String.format("券码 %s - %s", 
            voucherInfo.getVoucherCode(), 
            voucherInfo.getDiscountType().getName());
    }
    
    /**
     * 判断是否可以与其他优惠叠加
     */
    private boolean isStackable(VoucherInfo voucherInfo) {
        // 全场免费券码不可与其他优惠叠加
        return voucherInfo.getDiscountType() != VoucherDiscountType.FREE_ALL;
    }
}