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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wzj.soopin.content.service.UserMemberService;
import com.wzj.soopin.goods.domain.entity.Sku;
import com.wzj.soopin.goods.mapper.SkuMapper;
import com.wzj.soopin.order.domain.entity.Order;
import com.wzj.soopin.order.domain.entity.OrderItem;
import com.wzj.soopin.order.emum.OrderStatusEnum;
import com.wzj.soopin.order.service.OrderItemService;
import com.wzj.soopin.order.service.OrderService;
import com.wzj.soopin.transaction.config.EasypayConfig;
import com.wzj.soopin.transaction.convert.DivideConvert;
import com.wzj.soopin.transaction.convert.DivideDetailConvert;
import com.wzj.soopin.transaction.domain.bo.DivideBO;
import com.wzj.soopin.transaction.domain.bo.SeparateApplyBO;
import com.wzj.soopin.transaction.domain.bo.SeparateItemBO;
import com.wzj.soopin.transaction.domain.po.Divide;
import com.wzj.soopin.transaction.domain.po.DivideDetail;
import com.wzj.soopin.transaction.domain.po.DivideRuleDetail;
import com.wzj.soopin.transaction.domain.po.PayOrder;
import com.wzj.soopin.transaction.domain.vo.DivideRuleDetailVO;
import com.wzj.soopin.transaction.domain.vo.DivideRuleVO;
import com.wzj.soopin.transaction.domain.vo.DivideVO;
import com.wzj.soopin.transaction.enums.DivideRuleDetailType;
import com.wzj.soopin.transaction.enums.DivideStatus;
import com.wzj.soopin.transaction.enums.TransState;
import com.wzj.soopin.transaction.mapper.DivideDetailMapper;
import com.wzj.soopin.transaction.mapper.DivideMapper;
import com.wzj.soopin.transaction.service.IDivideRuleService;
import com.wzj.soopin.transaction.service.IDivideService;
import com.wzj.soopin.transaction.service.IEasypayService;
import com.wzj.soopin.transaction.service.PayOrderService;
import com.wzj.soopin.transaction.util.SnowFlake;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.enums.TenantType;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.SysTenant;
import org.dromara.system.domain.SysTenantExtend;
import org.dromara.system.domain.vo.SysTenantVo;
import org.dromara.system.mapper.SysTenantExtendMapper;
import org.dromara.system.service.ISysTenantService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static com.wzj.soopin.transaction.constans.EasypayConstants.TRACE_PREFIX;

/**
 * 分账服务实现类
 *
 * @author zcc
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class DivideServiceImpl extends ServiceImpl<DivideMapper, Divide> implements IDivideService {

    private final DivideDetailConvert detailConvert;

    private final DivideConvert divideConvert;

    private final OrderService orderService;

    private final PayOrderService payOrderService;

    private final IDivideRuleService ruleService;

    private final IEasypayService easypayService;

    private final ISysTenantService sysTenantService;

    private final SysTenantExtendMapper tenantExtendMapper;

    private final DivideMapper divideMapper;

    private final OrderItemService orderItemService;

    private final SkuMapper skuMapper;

    private final UserMemberService userMemberService;

    private final EasypayConfig easypayConfig;
    private final DivideDetailMapper divideDetailMapper;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(DivideBO bo) {

        Divide entity = divideConvert.toPo(bo);
        entity.setStatus(DivideStatus.PENDING.getCode());

        // 保存主分账信息
        boolean mainResult = super.save(entity);
        if (!mainResult) {
            throw new ServiceException("分账主信息保存失败，DivideBO: {}");
        }

        // 若明细列表不为空，批量保存分账明细信息
        if (!bo.getDetails().isEmpty()) {
            List<DivideDetail> detailEntities = bo.getDetails().stream()
                .peek(detailBO -> detailBO.setDivideId(entity.getId()))
                .map(detailConvert::toPo)
                .toList();

            boolean detailResult = divideDetailMapper.insertBatch(detailEntities);
            if (!detailResult) {
                throw new ServiceException("分账主信息保存失败，DivideBO: {}");
            }
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeById(Serializable id) {
        // 根据主分账记录的 ID 删除对应的分账明细
        boolean detailRemoveResult = divideDetailMapper.delete(new QueryWrapper<DivideDetail>().lambda().eq(DivideDetail::getDivideId, id)) > 0;
        if (!detailRemoveResult) {
            log.error("分账明细信息删除失败，分账记录 ID: {}", id);
            return false;
        }

        // 删除主分账记录
        boolean mainRemoveResult = super.removeById(id);
        if (!mainRemoveResult) {
            log.error("分账主信息删除失败，分账记录 ID: {}", id);
            return false;
        }
        return true;

    }

    @Override
    public DivideVO getVOById(Long divideId) {
        DivideVO divide = baseMapper.getVOById(divideId);
        if (divide == null) {
            return null;
        }
        List<DivideDetail> detailList = divideDetailMapper.selectList(Wrappers.lambdaQuery(DivideDetail.class).eq(DivideDetail::getDivideId, divideId));
        divide.setDetails(detailConvert.toVO(detailList));
        return divide;
    }

    @Override
    public Divide getByOrderNo(String orderNo) {
        return baseMapper.selectOne(new QueryWrapper<Divide>().lambda().eq(Divide::getOrderSn, orderNo));
    }

    /**
     * 订单金额分账
     * 商家先从订单总金额中分走租户中配置的比例后，剩余的按分账规则分给平台和推广等账户
     *
     * @param orderId 订单id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void divide(Long orderId) {
        //获取订单信息
        Order order = orderService.getById(orderId);
        Assert.notNull(order, () -> new ServiceException("订单不存在"));
        Assert.isTrue(Objects.equals(order.getStatus(), OrderStatusEnum.PAID.getValue()), () -> new ServiceException("订单未支付"));
        PayOrder payOrder = payOrderService.getById(order.getPayId());
        Assert.notNull(payOrder, () -> new ServiceException("支付单不存在"));
        Assert.isTrue(payOrder.getTransState() == TransState.PAID.getCode(), () -> new ServiceException("订单未支付"));
        Assert.isFalse(this.exists(Wrappers.lambdaQuery(Divide.class).eq(Divide::getOrderId, orderId)), () -> new ServiceException("已存在分账记录，无需再次分账"));
        //查找分账规则
        DivideRuleVO rule = ruleService.getVOByOrderType(order.getType());
        List<DivideRuleDetailVO> details = rule.getDetails();
        ruleService.checkRule(details.stream().map(detail -> BeanUtil.copyProperties(detail, DivideRuleDetail.class)).toList());
        List<OrderItem> orderItems = orderItemService.findByOrderId(orderId);
        for (OrderItem orderItem : orderItems) {
            Long orderItemId = orderItem.getId();
            //根据易生支付的合同查看手续费金额
            BigDecimal totalAmount = orderItem.getSalePrice().multiply(BigDecimal.valueOf(orderItem.getQuantity()));
            //计算订单可分配金额,订单只考虑整单退，不考虑单独退，所以直接计算订单金额
            //先生成主表信息
            Divide divide = divideMapper.selectByOrderIdAndOrderItemId(orderId, orderItemId);
            if (divide == null) {
                divide = Divide.builder()
                    .ruleId(rule.getId())
                    .orderId(orderId)
                    .orderSn(order.getOrderSn())
                    .orderItemId(orderItemId)
                    .orderItemMoney(totalAmount)
                    .separateBatchTrace(StrBuilder.create(TRACE_PREFIX).append(SnowFlake.getIdStr()).toString())
                    .status(DivideStatus.PENDING.getCode())
                    .build();
                super.save(divide);
            }
            Long divideId = divide.getId();
            List<SeparateItemBO> separateItemBOList = new ArrayList<>();
            // 从租户信息得到商户的分账比例,先分给商户
            Sku sku = skuMapper.selectById(orderItem.getSkuId());
            //商品所属租户
            SysTenantVo merchantTenant = sysTenantService.queryByTenantId(sku.getTenantId());
            rule.getDetails().stream()
                .filter(item -> item.getType() == TenantType.MERCHANT.getType())
                .findFirst()
                .ifPresent(ruleDetailVO -> {
                    divideSeller(order, totalAmount, ruleDetailVO, divideId, merchantTenant, separateItemBOList);
                });
            // 商户分完后分给代理和达人，最后剩余都给平台
            rule.getDetails().stream()
                .filter(item -> item.getType() == TenantType.AGENT.getType())
                .findFirst()
                .ifPresent(ruleDetailVO -> {
                     divideProxy(order, totalAmount, ruleDetailVO, divideId, merchantTenant.getCreateDept(), separateItemBOList);
                });
            rule.getDetails().stream()
                .filter(item -> item.getType() == TenantType.REFERENCE.getType())
                .findFirst()
                .ifPresent(ruleDetailVO -> {
                    divideReference(order, totalAmount, ruleDetailVO, divideId, order.getMemberId(), separateItemBOList);
                });
            rule.getDetails().stream()
                .filter(item -> item.getType() == TenantType.PLATFORM.getType())
                .findFirst()
                .ifPresent(ruleDetailVO -> {
                    dividePlatform(order, totalAmount, ruleDetailVO, divideId, separateItemBOList);
                });
            // 调用易生支付实时分账
            SeparateApplyBO separateApplyBO = SeparateApplyBO.builder()
                .orderId(order.getId())
                .payId(order.getPayId())
                .divideId(divide.getId())
                .transDate(payOrder.getEndTransDate())
                .transSumAmt(payOrder.getTransAmount())
                .transSumCount((long) separateItemBOList.size())
                .separateBatchTrace(divide.getSeparateBatchTrace())
                .separateItemBOList(separateItemBOList)
                .build();
            easypayService.separateApply(separateApplyBO);
        }
//        String sss = "{\"divideId\":1966406009702875137,\"orderId\":1965688269369024513,\"payId\":1965688289677844482,\"separateBatchTrace\":\"1966401173213224961\",\"separateItemBOList\":[{\"divideDetailId\":1966406024735260674,\"receiveMchtCode\":\"KK0000000000985\",\"sepaFeeRatio\":95,\"sepaRatio\":95,\"separateTrade\":\"WZJ_1966401200823730176\"},{\"divideDetailId\":1966406024768815105,\"receiveMchtCode\":\"631000000003325\",\"sepaFeeRatio\":5,\"sepaRatio\":5,\"separateTrade\":\"WZJ_1966401200882450432\"}],\"transDate\":\"2025-09-10 16:06:33\",\"transSumAmt\":100,\"transSumCount\":2}";
//        SeparateApplyBO separateApplyBO = JSONObject.parseObject(sss, SeparateApplyBO.class);
//        easypayService.separateApply(separateApplyBO);
    }

    /**
     * 商户分账
     *
     * @param order
     * @param totalAmount        总金额
     * @param ruleDetailVO       分账规则详情
     * @param divideId           分账总表id
     * @param tenant             商户所属租户
     * @param separateItemBOList 分账请求详情项
     */
    private void divideSeller(Order order, BigDecimal totalAmount, DivideRuleDetailVO ruleDetailVO, Long divideId, SysTenantVo tenant, List<SeparateItemBO> separateItemBOList) {
        //获取商户的账户信息
        String mchtCode = getMchtCode(tenant.getTenantId());
        // TODO 商户的分账百分比占比值从模板中获取，联调易生暂时写死
        int divideRate = 95;
        //计算商户的分账金额
        BigDecimal sellerAmount = totalAmount.multiply(BigDecimal.valueOf(divideRate)).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        String separateTrade = StrBuilder.create(TRACE_PREFIX).append(SnowFlake.getIdStr()).toString();
        //生成商户的分账明细
        DivideDetail divideDetail = DivideDetail.builder()
            .separateTrade(separateTrade)
            .divideId(divideId)
            .ruleDetailId(ruleDetailVO.getId())
            .orderId(order.getId())
            .orderSn(order.getOrderSn())
            .accountCode(mchtCode)
            .money(sellerAmount)
            .moneyPercent(divideRate)
            .feePercent(ruleDetailVO.getFeePercent())
            .type(TenantType.MERCHANT.getType())
            .status(DivideStatus.PENDING.getCode())
            .build();
        divideDetailMapper.insert(divideDetail);
        SeparateItemBO separateItemBO = SeparateItemBO.builder()
            .divideDetailId(divideDetail.getId())
            .separateTrade(separateTrade)
            .receiveMchtCode(mchtCode)
            .sepaRatio((long) divideRate)
            .sepaFeeRatio(Long.valueOf(ruleDetailVO.getFeePercent()))
            .build();
        separateItemBOList.add(separateItemBO);
    }

    /**
     * 代理商分账
     *
     * @param order
     * @param totalAmount        总金额
     * @param rule               代理商的分账规则详情
     * @param divideId           分账总表id
     * @param createDept         创建该商铺租户的部门，用于获取代理商的租户
     * @param separateItemBOList
     */
    private void divideProxy(Order order, BigDecimal totalAmount, DivideRuleDetailVO rule, Long divideId, Long createDept, List<SeparateItemBO> separateItemBOList) {
        //获取代理人的账户信息
        SysTenant proxyTenant = sysTenantService.queryByDeptId(createDept);
        String mchtCode = getMchtCode(proxyTenant.getTenantId());
        //计算代理人的分账金额
        BigDecimal proxyAmount = BigDecimal.valueOf(rule.getMoneyPercent()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP).multiply(totalAmount);
        String separateTrade = StrBuilder.create(TRACE_PREFIX).append(SnowFlake.getIdStr()).toString();
        DivideDetail divideDetail = DivideDetail.builder()
            .separateTrade(separateTrade)
            .divideId(divideId)
            .ruleDetailId(rule.getId())
            .orderId(order.getId())
            .orderSn(order.getOrderSn())
            .accountCode(mchtCode)
            .money(proxyAmount)
            .moneyPercent(rule.getMoneyPercent())
            .feePercent(rule.getFeePercent())
            .type(TenantType.AGENT.getType())
            .status(DivideStatus.PENDING.getCode())
            .build();
        divideDetailMapper.insert(divideDetail);
        SeparateItemBO separateItemBO = SeparateItemBO.builder()
            .divideDetailId(divideDetail.getId())
            .separateTrade(separateTrade)
            .receiveMchtCode(mchtCode)
            .sepaRatio(Long.valueOf(rule.getMoneyPercent()))
            .sepaFeeRatio(Long.valueOf(rule.getFeePercent()))
            .build();
        separateItemBOList.add(separateItemBO);

    }

    /**
     * 达人分账
     *
     * @param order
     * @param totalAmount
     * @param rule
     * @param divideId
     * @param memberId
     * @param separateItemBOList
     */
    private void divideReference(Order order, BigDecimal totalAmount, DivideRuleDetailVO rule, Long divideId, Long memberId, List<SeparateItemBO> separateItemBOList) {
        //获取达人的账户信息
        String mchtCode = getMchtCodeByMemberId(memberId);
        //计算达人的分账金额
        BigDecimal referencAmount = BigDecimal.valueOf(rule.getMoneyPercent()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP).multiply(totalAmount);
        String separateTrade = StrBuilder.create(TRACE_PREFIX).append(SnowFlake.getIdStr()).toString();
        DivideDetail divideDetail = DivideDetail.builder()
            .separateTrade(separateTrade)
            .divideId(divideId)
            .ruleDetailId(rule.getId())
            .orderId(order.getId())
            .orderSn(order.getOrderSn())
            .accountCode(mchtCode)
            .money(referencAmount)
            .moneyPercent(rule.getMoneyPercent())
            .feePercent(rule.getFeePercent())
            .type(TenantType.REFERENCE.getType())
            .status(DivideStatus.PENDING.getCode())
            .build();
        divideDetailMapper.insert(divideDetail);
        SeparateItemBO separateItemBO = SeparateItemBO.builder()
            .divideDetailId(divideDetail.getId())
            .separateTrade(separateTrade)
            .receiveMchtCode(mchtCode)
            .sepaRatio(Long.valueOf(rule.getMoneyPercent()))
            .sepaFeeRatio(Long.valueOf(rule.getFeePercent()))
            .build();
        separateItemBOList.add(separateItemBO);

    }


    /**
     * 平台分账
     *
     * @param order
     * @param totalAmount
     * @param rule
     * @param divideId
     * @param separateItemBOList
     */
    private void dividePlatform(Order order, BigDecimal totalAmount, DivideRuleDetailVO rule, Long divideId, List<SeparateItemBO> separateItemBOList) {
        //获取平台的账户信息
        String mchtCode = easypayConfig.getMchtCode();
        //计算平台的分账金额
        BigDecimal platformAmount = BigDecimal.valueOf(rule.getMoneyPercent()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP).multiply(totalAmount);
        String separateTrade = StrBuilder.create(TRACE_PREFIX).append(SnowFlake.getIdStr()).toString();
        DivideDetail divideDetail = DivideDetail.builder()
            .separateTrade(separateTrade)
            .divideId(divideId)
            .ruleDetailId(rule.getId())
            .orderId(order.getId())
            .orderSn(order.getOrderSn())
            .accountCode(mchtCode)
            .money(platformAmount)
            .moneyPercent(rule.getMoneyPercent())
            .feePercent(rule.getFeePercent())
            .type(TenantType.PLATFORM.getType())
            .status(DivideStatus.PENDING.getCode())
            .build();
        divideDetailMapper.insert(divideDetail);
        SeparateItemBO separateItemBO = SeparateItemBO.builder()
            .divideDetailId(divideDetail.getId())
            .separateTrade(separateTrade)
            .receiveMchtCode(mchtCode)
            .sepaRatio(Long.valueOf(rule.getMoneyPercent()))
            .sepaFeeRatio(Long.valueOf(rule.getFeePercent()))
            .build();
        separateItemBOList.add(separateItemBO);
    }

    @Override
    public boolean cancelDivide(String orderNo) {
        return false;
    }

    @Override
    public boolean divideCallback(String divideNo) {
        return false;
    }

    @Override
    public boolean cancelDivideCallback(String divideNo) {
        return false;
    }


    /**
     * 获取平台或商家或推广或达人在易生侧的商户号
     *
     * @param tenantId
     * @return
     */
    private String getMchtCode(String tenantId) {
        // 从租户信息中获得商家在易生侧的商户号
        SysTenantExtend sysTenantExtend = tenantExtendMapper.selectOne(Wrappers.lambdaQuery(SysTenantExtend.class)
            .eq(SysTenantExtend::getTenantId, tenantId).last("limit 1"));
        String mchtCode = sysTenantExtend.getMchtCode();
        Assert.notBlank(mchtCode, () -> new ServiceException("未维护商户在易生侧的商户号信息"));
        return mchtCode;
    }


    /**
     * 通过会员id获得其对应的达人的商户号
     *
     * @param memberId
     * @return
     */
    private String getMchtCodeByMemberId(Long memberId) {
        SysTenant sysTenant= userMemberService.getReferenceTenantByMemberId(memberId);
        return getMchtCode(sysTenant.getTenantId());
    }


}
