package com.wzj.soopin.transaction.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wzj.soopin.transaction.convert.DivideRuleConvert;
import com.wzj.soopin.transaction.convert.DivideRuleDetailConvert;
import com.wzj.soopin.transaction.domain.bo.DivideRuleBO;
import com.wzj.soopin.transaction.domain.bo.DivideRuleDetailBO;
import com.wzj.soopin.transaction.domain.po.DivideRule;
import com.wzj.soopin.transaction.domain.po.DivideRuleDetail;
import com.wzj.soopin.transaction.domain.vo.DivideRuleVO;
import com.wzj.soopin.transaction.enums.DivideRuleStatus;
import com.wzj.soopin.transaction.mapper.DivideRuleDetailMapper;
import com.wzj.soopin.transaction.mapper.DivideRuleMapper;
import com.wzj.soopin.transaction.service.IDivideRuleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.enums.TenantType;
import org.dromara.common.core.exception.ServiceException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 分账服务实现类
 *
 * @author zcc
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class DivideRuleServiceImpl extends ServiceImpl<DivideRuleMapper, DivideRule> implements IDivideRuleService {

    private final DivideRuleDetailMapper detailMapper;

    private final DivideRuleDetailConvert detailConvert;

    private final DivideRuleConvert convert;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean save(DivideRuleBO bo) {
        DivideRule entity = convert.toPo(bo);
        entity.setStatus(DivideRuleStatus.ON.getCode());
        // 保存主分账信息
        save(entity);
        List<DivideRuleDetailBO> details = bo.getDetails();
        Assert.notEmpty(details, () -> new ServiceException("分账规则详情不能为空"));
        checkRule(details.stream().map(detail -> BeanUtil.copyProperties(detail, DivideRuleDetail.class)).toList());
        List<DivideRuleDetail> detailEntities = details.stream()
            .peek(detailBO -> detailBO.setRuleId(entity.getId()))
            .map(detailConvert::toPo)
            .toList();
        detailMapper.insertBatch(detailEntities);
        return true;
    }

    @Override
    public void update(DivideRuleBO bo) {
        DivideRule divideRule = this.getById(bo.getId());
        Assert.notNull(divideRule, () -> new ServiceException("未找到该分账规则"));
        Assert.isTrue(divideRule.getStatus().equals(DivideRuleStatus.OFF.getCode()), () -> new ServiceException("请先停用状态规则"));
        List<DivideRuleDetailBO> details = bo.getDetails();
        Assert.notEmpty(details, () -> new ServiceException("分账规则详情不能为空"));
        checkRule(details.stream().map(detail -> BeanUtil.copyProperties(detail, DivideRuleDetail.class)).toList());
        detailMapper.delete(new QueryWrapper<DivideRuleDetail>().lambda().eq(DivideRuleDetail::getRuleId, bo.getId()));
        List<DivideRuleDetail> detailEntities = details.stream()
            .peek(detailBO -> detailBO.setRuleId(bo.getId()))
            .map(detailConvert::toPo)
            .toList();
        detailMapper.insertBatch(detailEntities);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeById(Serializable id) {
        DivideRule divideRule = this.getById(id);
        Assert.notNull(divideRule, () -> new ServiceException("未找到该分账规则"));
        Assert.isTrue(divideRule.getStatus().equals(DivideRuleStatus.OFF.getCode()), () -> new ServiceException("请先停用状态规则"));
        // 根据主分账记录的 ID 删除对应的分账明细
        boolean detailRemoveResult = detailMapper.delete(new QueryWrapper<DivideRuleDetail>().lambda().eq(DivideRuleDetail::getRuleId, id)) > 0;
        boolean mainRemoveResult = false;
        if(detailRemoveResult){
            // 删除主分账记录
            mainRemoveResult = super.removeById(id);
        }
        return detailRemoveResult && mainRemoveResult;
    }

    @Override
    public DivideRuleVO getVOById(Long divideId) {
        DivideRule divideRule = baseMapper.selectById(divideId);
        if (divideRule == null) {
            return null;
        }
        List<DivideRuleDetail> detailList = detailMapper.selectList(new QueryWrapper<DivideRuleDetail>().lambda()
            .eq(DivideRuleDetail::getRuleId, divideId));
        DivideRuleVO vo = convert.toVO(divideRule);
        vo.setDetails(detailConvert.toVO(detailList));
        return vo;
    }

    @Override
    public DivideRuleVO getVOByOrderType(Integer orderType) {
        List<DivideRule> divideRuleList = baseMapper.selectList(new QueryWrapper<DivideRule>().lambda()
            .eq(DivideRule::getType, orderType)
            .eq(DivideRule::getStatus, DivideRuleStatus.ON.getCode()));
        Assert.notEmpty(divideRuleList, () -> new ServiceException("未找到品类的分账规则"));
        Assert.isTrue(divideRuleList.size() == 1, () -> new ServiceException("品类分账规则不唯一"));
        DivideRule divideRule = divideRuleList.get(0);
        List<DivideRuleDetail> detailList = detailMapper.selectList(new QueryWrapper<DivideRuleDetail>().lambda()
            .eq(DivideRuleDetail::getRuleId, divideRule.getId()));
        DivideRuleVO vo = convert.toVO(divideRule);
        vo.setDetails(detailConvert.toVO(detailList));
        return vo;
    }

    @Override
    public void changeStatus(Long id, Integer status) {
        DivideRuleStatus divideRuleStatus = DivideRuleStatus.valueOf(status);
        Assert.notNull(divideRuleStatus, () -> new ServiceException("分账状态错误"));
        DivideRule divideRule = this.getById(id);
        Assert.notNull(divideRule, () -> new ServiceException("未找到该分账规则"));
        Assert.isTrue(status.equals(DivideRuleStatus.ON.getCode()) || status.equals(DivideRuleStatus.OFF.getCode()), () -> new ServiceException("停/启用状态错误"));
        this.updateById(DivideRule.builder().id(id).status(divideRuleStatus.getCode()).build());
    }

    /**
     * 校验分账规则详情
     *
     * @param details
     */
    @Override
    public void checkRule(List<DivideRuleDetail> details) {
        Map<Integer, List<DivideRuleDetail>> map = details.stream().collect(Collectors.groupingBy(DivideRuleDetail::getType));
        List<DivideRuleDetail> details1 = map.get(TenantType.MERCHANT.getType());
        Assert.isTrue(details1 != null && details1.size() == 1, () -> new ServiceException("商户分账详情不能为空"));
        List<DivideRuleDetail> details2 = map.get(TenantType.PLATFORM.getType());
        Assert.isTrue(details2 != null && details2.size() == 1, () -> new ServiceException("平台分账详情不能为空"));
        long totalMoneyRatio = 0L;
        long totalFeeRatio = 0L;
        for (DivideRuleDetail detail : details) {
            totalMoneyRatio += detail.getMoneyPercent();
            totalFeeRatio += detail.getFeePercent();
        }
        Assert.isTrue(totalMoneyRatio == 100L, () -> new ServiceException("金额分账比例之和未等于100%"));
        Assert.isTrue(totalFeeRatio == 100L, () -> new ServiceException("手续费分账比例之和未等于100%"));
    }
}
