package com.ruoyi.app.order;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.ruoyi.app.order.dto.OrderCreatItem;
import com.ruoyi.system.domain.PosOrder;
import com.ruoyi.system.domain.PosOrderPromotion;
import com.ruoyi.system.dto.PromotionCalcRequest;
import com.ruoyi.system.dto.PromotionCalcResponse;
import com.ruoyi.system.dto.PromotionCalcResponse.PromotionDetail;
import com.ruoyi.system.mapper.PosOrderPromotionMapper;
import com.ruoyi.system.service.IPromotionCalcService;
import com.ruoyi.system.service.IPromotionUserCouponService;

/**
 * 订单促销辅助类
 *
 * 在用户下单时处理促销算价、优惠字段回填、快照写入、优惠券标记等逻辑。
 * 每个方法职责单一，由 UserOrderController.createOrderChild 按顺序调用。
 */
@Component
public class OrderPromotionHelper {

    private static final Logger logger = LoggerFactory.getLogger(OrderPromotionHelper.class);

    @Autowired
    private IPromotionCalcService promotionCalcService;

    @Autowired
    private PosOrderPromotionMapper posOrderPromotionMapper;

    @Autowired
    private IPromotionUserCouponService promotionUserCouponService;

    /**
     * 调用促销算价服务
     *
     * @param item   子订单输入项（含 cartItems, couponId, forcePath）
     * @param userId 用户ID
     * @return 算价结果；如果前端未传 cartItems 则返回 null（跳过促销）
     */
    public PromotionCalcResponse calcPromotion(OrderCreatItem item, Long userId) {
        if (item.getCartItems() == null || item.getCartItems().isEmpty()) {
            return null;
        }
        PromotionCalcRequest request = new PromotionCalcRequest();
        request.setStoreId(item.getMdId());
        request.setItems(item.getCartItems());
        request.setCouponId(item.getCouponId());
        request.setForcePath(item.getForcePath());

        return promotionCalcService.calculate(request, userId);
    }

    /**
     * 校验前端传入的优惠金额与后端算价结果是否一致（宽松校验，仅记录差异不阻断下单）
     *
     * @param calc           后端算价结果
     * @param frontendReduce 前端传入的优惠金额(分)
     */
    public void validatePromotionAmount(PromotionCalcResponse calc, Integer frontendReduce) {
        if (calc == null || frontendReduce == null) {
            return;
        }
        BigDecimal backendReduce = calc.getOriginalAmount().subtract(calc.getFinalAmount());
        int backendReduceCents = backendReduce.multiply(new BigDecimal("100")).intValue();
        int diff = Math.abs(backendReduceCents - frontendReduce);
        if (diff > 1) {
            logger.warn("订单优惠金额校验差异：后端计算优惠={}分, 前端传入={}分, 差异={}分",
                    backendReduceCents, frontendReduce, diff);
        }
    }

    /**
     * 将算价结果回填到 PosOrder 实体的优惠字段
     *
     * PosOrder 优惠字段说明：
     * - mdActivity / mdSalesName / mdSalesReduction(分) — 门店促销
     * - mdYhId / mdYhName / mdDiscountAmount(分) — 门店优惠券
     *
     * @param posOrder 目标订单实体（会被修改）
     * @param calc     算价结果，可为 null
     */
    public void fillPromotionFields(PosOrder posOrder, PromotionCalcResponse calc) {
        if (calc == null || calc.getDetails() == null) {
            return;
        }
        int totalPromotionReduceCents = 0;
        String promoName = null;
        Long promoActivityId = null;

        for (PromotionDetail detail : calc.getDetails()) {
            if ("promotion".equals(detail.getType())) {
                // 累加所有促销减免（满减+新客立减）
                totalPromotionReduceCents += detail.getReduce().intValue();
                // 取第一个非新客立减的促销名称作为主名称
                if (promoName == null && detail.getSubType() != null && detail.getSubType() != 4) {
                    promoName = detail.getName();
                    promoActivityId = detail.getRefId();
                }
            }
            else if ("coupon".equals(detail.getType())) {
                posOrder.setMdYhId(calc.getCouponId());
                posOrder.setMdYhName(detail.getName());
                posOrder.setMdDiscountAmount(detail.getReduce().intValue());
            }
        }

        if (totalPromotionReduceCents > 0) {
            posOrder.setMdActivity(promoActivityId);
            posOrder.setMdSalesName(promoName);
            posOrder.setMdSalesReduction(totalPromotionReduceCents);
        }
    }

    /**
     * 将促销明细批量写入 pos_order_promotion 快照表
     *
     * @param orderId       PosOrder 保存后的自增 ID
     * @param calc          算价结果
     */
    public void savePromotionSnapshots(Long orderId, PromotionCalcResponse calc) {
        if (calc == null || calc.getDetails() == null || calc.getDetails().isEmpty()) {
            return;
        }
        List<PosOrderPromotion> snapshots = new ArrayList<>();
        boolean isFirst = true;

        for (PromotionDetail detail : calc.getDetails()) {
            PosOrderPromotion snapshot = new PosOrderPromotion();
            snapshot.setOrderId(orderId);
            snapshot.setPromoType("promotion".equals(detail.getType()) ? 1 : 2);
            snapshot.setPromoSubType(detail.getSubType());
            snapshot.setPromoId(detail.getRefId());
            snapshot.setPromoName(detail.getName());
            snapshot.setPromoDetail(JSON.toJSONString(detail));
            snapshot.setReduceAmount(detail.getReduce());
            snapshot.setCreateTime(new Date());

            // 优惠券时关联用户券ID
            if ("coupon".equals(detail.getType()) && calc.getCouponId() != null) {
                snapshot.setUserCouponId(calc.getCouponId());
            }

            // 第一条记录写入路径对比摘要
            if (isFirst) {
                snapshot.setPathSummary(buildPathSummary(calc));
                isFirst = false;
            }

            snapshots.add(snapshot);
        }

        posOrderPromotionMapper.insertBatch(snapshots);
    }

    /**
     * 标记用户优惠券为已使用
     *
     * @param couponId 用户优惠券 ID（promotion_user_coupon.id）
     * @param orderId  关联的订单 ID
     * @param userId   用户 ID（校验归属）
     */
    public void markCouponUsed(Long couponId, Long orderId, Long userId) {
        if (couponId == null) {
            return;
        }
        promotionUserCouponService.markAsUsed(couponId, orderId, userId);
    }

    // ==================== 内部工具方法 ====================

    /**
     * 构建路径对比摘要
     * 示例："满减路径¥33.00 vs 折扣路径¥39.00, 选择满减"
     */
    private String buildPathSummary(PromotionCalcResponse calc) {
        if (calc.getPathA() == null || calc.getPathB() == null) {
            return null;
        }
        String pathALabel = calc.getPathA().getLabel();
        String pathBLabel = calc.getPathB().getLabel();
        String chosen = "A".equals(calc.getOptimalPath()) ? pathALabel : pathBLabel;
        return pathBLabel + "路径¥" + calc.getPathB().getSubtotal()
                + " vs " + pathALabel + "路径¥" + calc.getPathA().getSubtotal()
                + ", 选择" + chosen;
    }

    /**
     * BigDecimal(元) 转 Integer(分)
     */
    private int toCents(BigDecimal amount) {
        if (amount == null) {
            return 0;
        }
        return amount.multiply(new BigDecimal("100")).intValue();
    }
}
