package com.ruoyi.system.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.system.mapper.PromotionCouponBatchMapper;
import com.ruoyi.system.mapper.PromotionCouponRuleMapper;
import com.ruoyi.system.domain.PromotionCouponBatch;
import com.ruoyi.system.domain.PromotionCouponRule;
import com.ruoyi.system.service.IPromotionCouponBatchService;

/**
 * 优惠券批次Service业务层处理
 *
 * @author ruoyi
 * @date 2024-05-30
 */
@Service
public class PromotionCouponBatchServiceImpl extends ServiceImpl<BaseMapper<PromotionCouponBatch>, PromotionCouponBatch> implements IPromotionCouponBatchService
{
    @Autowired
    private PromotionCouponBatchMapper promotionCouponBatchMapper;

    @Autowired
    private PromotionCouponRuleMapper ruleMapper;

    @Autowired
    private PromotionDiscountLimitChecker discountLimitChecker;

    /**
     * 创建优惠券批次（含规则）
     */
    @Override
    @Transactional
    public boolean createBatch(PromotionCouponBatch batch, PromotionCouponRule rule)
    {
        // 校验：优惠幅度限制（平台开关控制，超上限拒绝）
        discountLimitChecker.checkCouponBatch(batch, rule);
        Date now = new Date();
        batch.setRemainCount(batch.getTotalCount());
        batch.setReceivedCount(0);
        batch.setCreateTime(now);
        batch.setUpdateTime(now);
        // 根据开始时间设置状态
        if (batch.getStartTime() != null && batch.getStartTime().before(now))
        {
            batch.setStatus(1);
        }
        else
        {
            batch.setStatus(0);
        }
        int rows = promotionCouponBatchMapper.insert(batch);
        // 设置规则的批次ID并插入
        if (rule != null)
        {
            rule.setBatchId(batch.getId());
            ruleMapper.insert(rule);
        }
        return rows > 0;
    }
    /**
     * 创建优惠券批次（含多条规则，多商品券）
     */
    @Override
    @Transactional
    public boolean createBatch(PromotionCouponBatch batch, List<PromotionCouponRule> rules)
    {
        // 校验：优惠幅度限制（平台开关控制，超上限拒绝）
        discountLimitChecker.checkCouponBatch(batch, rules);
        Date now = new Date();
        batch.setRemainCount(batch.getTotalCount());
        batch.setReceivedCount(0);
        batch.setCreateTime(now);
        batch.setUpdateTime(now);
        if (batch.getStartTime() != null && batch.getStartTime().before(now))
        {
            batch.setStatus(1);
        }
        else
        {
            batch.setStatus(0);
        }
        int rows = promotionCouponBatchMapper.insert(batch);
        if (rules != null && !rules.isEmpty())
        {
            for (PromotionCouponRule r : rules)
            {
                r.setBatchId(batch.getId());
                ruleMapper.insert(r);
            }
        }
        return rows > 0;
    }

    /**
     * 查询批次详情（含规则）
     */
    @Override
    public PromotionCouponBatch selectBatchWithRule(Long id)
    {
        PromotionCouponBatch batch = promotionCouponBatchMapper.selectById(id);
        if (batch != null)
        {
            PromotionCouponRule rule = ruleMapper.selectRuleByBatchId(id);
            batch.setRule(rule);
            List<PromotionCouponRule> rules = ruleMapper.selectRulesByBatchId(id);
            batch.setRules(rules);
        }
        return batch;
    }

    /**
     * 下架批次（仅进行中）
     */
    @Override
    public boolean offShelfBatch(Long id)
    {
        PromotionCouponBatch existing = promotionCouponBatchMapper.selectById(id);
        if (existing == null || existing.getStatus() != 1)
        {
            throw new ServiceException("只能下架进行中的优惠券");
        }
        PromotionCouponBatch batch = new PromotionCouponBatch();
        batch.setId(id);
        batch.setStatus(3);
        batch.setUpdateTime(new Date());
        return promotionCouponBatchMapper.updateById(batch) > 0;
    }

    /**
     * 修改优惠券批次（含规则）
     */
    @Override
    @Transactional
    public boolean updateBatch(PromotionCouponBatch batch, PromotionCouponRule rule)
    {
        PromotionCouponBatch existing = promotionCouponBatchMapper.selectById(batch.getId());
        if (existing == null)
        {
            throw new ServiceException("优惠券不存在");
        }
        if (existing.getStatus() != 0 && existing.getStatus() != 1)
        {
            throw new ServiceException("只能修改未开始或进行中的优惠券");
        }
        batch.setUpdateTime(new Date());
        // 如果修改了总量，同步调整剩余数量
        if (batch.getTotalCount() != null && !batch.getTotalCount().equals(existing.getTotalCount()))
        {
            int delta = batch.getTotalCount() - (existing.getTotalCount() != null ? existing.getTotalCount() : 0);
            batch.setRemainCount((existing.getRemainCount() != null ? existing.getRemainCount() : 0) + delta);
        }
        if (existing.getReceivedCount() != null && existing.getReceivedCount() > 0)
        {
            // 已有人领取：只更新批次级别字段；若试图修改规则则拒绝
            if (rule != null)
            {
                List<PromotionCouponRule> existingRules = ruleMapper.selectRulesByBatchId(batch.getId());
                List<PromotionCouponRule> newRules = new ArrayList<>();
                newRules.add(rule);
                if (couponRulesDifferent(existingRules, newRules))
                {
                    throw new ServiceException("该优惠券已被领取，无法修改适用商品/规则");
                }
            }
            promotionCouponBatchMapper.updateById(batch);
        }
        else
        {
            // 无人领取，更新批次并替换规则；替换前校验新规则优惠幅度（已被领取且规则未变的路径不触发，存量豁免）
            if (batch.getCouponType() == null)
            {
                batch.setCouponType(existing.getCouponType());
            }
            discountLimitChecker.checkCouponBatch(batch, rule);
            promotionCouponBatchMapper.updateById(batch);
            if (rule != null)
            {
                // 删除旧规则
                ruleMapper.delete(new LambdaQueryWrapper<PromotionCouponRule>()
                        .eq(PromotionCouponRule::getBatchId, batch.getId()));
                // 插入新规则
                rule.setBatchId(batch.getId());
                ruleMapper.insert(rule);
            }
        }
        return true;
    }
    /**
     * 修改优惠券批次（含多条规则，多商品券）
     */
    @Override
    @Transactional
    public boolean updateBatch(PromotionCouponBatch batch, List<PromotionCouponRule> rules)
    {
        PromotionCouponBatch existing = promotionCouponBatchMapper.selectById(batch.getId());
        if (existing == null)
        {
            throw new ServiceException("优惠券不存在");
        }
        if (existing.getStatus() != 0 && existing.getStatus() != 1)
        {
            throw new ServiceException("只能修改未开始或进行中的优惠券");
        }
        batch.setUpdateTime(new Date());
        if (batch.getTotalCount() != null && !batch.getTotalCount().equals(existing.getTotalCount()))
        {
            int delta = batch.getTotalCount() - (existing.getTotalCount() != null ? existing.getTotalCount() : 0);
            batch.setRemainCount((existing.getRemainCount() != null ? existing.getRemainCount() : 0) + delta);
        }
        if (existing.getReceivedCount() != null && existing.getReceivedCount() > 0)
        {
            // 已有人领取：只更新批次级别字段；若试图修改规则则拒绝
            if (rules != null && !rules.isEmpty())
            {
                List<PromotionCouponRule> existingRules = ruleMapper.selectRulesByBatchId(batch.getId());
                if (couponRulesDifferent(existingRules, rules))
                {
                    throw new ServiceException("该优惠券已被领取，无法修改适用商品/规则");
                }
            }
            promotionCouponBatchMapper.updateById(batch);
        }
        else
        {
            // 无人领取，替换规则前校验新规则优惠幅度（已被领取且规则未变的路径不触发，存量豁免）
            if (batch.getCouponType() == null)
            {
                batch.setCouponType(existing.getCouponType());
            }
            discountLimitChecker.checkCouponBatch(batch, rules);
            promotionCouponBatchMapper.updateById(batch);
            if (rules != null && !rules.isEmpty())
            {
                // 删除旧规则
                ruleMapper.delete(new LambdaQueryWrapper<PromotionCouponRule>()
                        .eq(PromotionCouponRule::getBatchId, batch.getId()));
                // 插入新规则（多条）
                for (PromotionCouponRule r : rules)
                {
                    r.setBatchId(batch.getId());
                    ruleMapper.insert(r);
                }
            }
        }
        return true;
    }

    /**
     * 删除优惠券批次（仅未开始且无人领取）
     */
    @Override
    @Transactional
    public boolean deleteBatch(Long id)
    {
        PromotionCouponBatch existing = promotionCouponBatchMapper.selectById(id);
        if (existing == null)
        {
            throw new ServiceException("优惠券不存在");
        }
        boolean hasReceived = existing.getReceivedCount() != null && existing.getReceivedCount() > 0;
        if (hasReceived || (existing.getStatus() != 0 && existing.getStatus() != 1))
        {
            throw new ServiceException("只能删除未开始或进行中且无人领取的优惠券");
        }
        // 删除规则
        ruleMapper.delete(new LambdaQueryWrapper<PromotionCouponRule>()
                .eq(PromotionCouponRule::getBatchId, id));
        // 删除批次
        promotionCouponBatchMapper.deleteById(id);
        return true;
    }

    /**
     * 比较新旧优惠券规则是否一致（用于判断已领取券是否在尝试修改规则）。
     * 按 productId 对齐逐条比较 discountRate/threshold/amount/isMutex，与顺序无关。
     */
    private boolean couponRulesDifferent(List<PromotionCouponRule> oldRules, List<PromotionCouponRule> newRules)
    {
        int oldSize = oldRules == null ? 0 : oldRules.size();
        int newSize = newRules == null ? 0 : newRules.size();
        if (oldSize != newSize)
        {
            return true;
        }
        Map<Long, PromotionCouponRule> oldMap = new HashMap<>();
        if (oldRules != null)
        {
            for (PromotionCouponRule r : oldRules)
            {
                oldMap.put(r.getProductId(), r);
            }
        }
        if (newRules != null)
        {
            for (PromotionCouponRule n : newRules)
            {
                PromotionCouponRule o = oldMap.get(n.getProductId());
                if (o == null)
                {
                    return true;
                }
                if (compareDecimal(o.getDiscountRate(), n.getDiscountRate()) != 0
                        || compareDecimal(o.getThreshold(), n.getThreshold()) != 0
                        || compareDecimal(o.getAmount(), n.getAmount()) != 0
                        || !Objects.equals(o.getIsMutex(), n.getIsMutex()))
                {
                    return true;
                }
            }
        }
        return false;
    }

    private int compareDecimal(BigDecimal a, BigDecimal b)
    {
        BigDecimal x = a == null ? BigDecimal.ZERO : a;
        BigDecimal y = b == null ? BigDecimal.ZERO : b;
        return x.compareTo(y);
    }
}
