package com.gxwebsoft.shop.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.gxwebsoft.shop.dto.ShopDealerRefundDto;
import com.gxwebsoft.shop.entity.ShopDealerCapital;
import com.gxwebsoft.shop.entity.ShopDealerOrder;
import com.gxwebsoft.shop.entity.ShopDealerUser;
import com.gxwebsoft.shop.entity.ShopOrder;
import com.gxwebsoft.shop.service.ShopDealerCapitalService;
import com.gxwebsoft.shop.service.ShopDealerCommissionRollbackService;
import com.gxwebsoft.shop.service.ShopDealerOrderService;
import com.gxwebsoft.shop.service.ShopDealerUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class ShopDealerCommissionRollbackServiceImpl implements ShopDealerCommissionRollbackService {

    private static final int FLOW_TYPE_COMMISSION_INCOME = 10;
    private static final int FLOW_TYPE_COMMISSION_UNFREEZE_MARKER = 50;
    private static final int FLOW_TYPE_DELIVERY_REWARD = 60;

    @Resource
    private ShopDealerCapitalService shopDealerCapitalService;

    @Resource
    private ShopDealerUserService shopDealerUserService;

    @Resource
    private ShopDealerOrderService shopDealerOrderService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean rollbackOnOrderRefund(ShopOrder order, BigDecimal refundAmount) {
        if (order == null || order.getTenantId() == null || order.getOrderNo() == null || order.getOrderNo().isBlank()) {
            return true;
        }

        Integer tenantId = order.getTenantId();
        String orderNo = order.getOrderNo();

        BigDecimal orderBaseAmount = ObjectUtil.defaultIfNull(order.getPayPrice(), order.getTotalPrice());
        BigDecimal ratio = resolveRefundRatio(orderBaseAmount, refundAmount);

        List<ShopDealerCapital> capitals = shopDealerCapitalService.list(
            new LambdaQueryWrapper<ShopDealerCapital>()
                .eq(ShopDealerCapital::getTenantId, tenantId)
                .eq(ShopDealerCapital::getOrderNo, orderNo)
                .in(ShopDealerCapital::getFlowType, FLOW_TYPE_COMMISSION_INCOME, FLOW_TYPE_DELIVERY_REWARD)
                .isNotNull(ShopDealerCapital::getUserId)
                .isNotNull(ShopDealerCapital::getMoney)
                .gt(ShopDealerCapital::getMoney, BigDecimal.ZERO)
        );

        if (capitals == null || capitals.isEmpty()) {
            // 仍标记分销订单失效，避免后续统计误判
            markDealerOrderInvalid(tenantId, orderNo);
            return true;
        }

        Map<Integer, BigDecimal> freezeDeductByUser = new HashMap<>();
        Map<Integer, BigDecimal> moneyDeductByUser = new HashMap<>();
        Map<Integer, BigDecimal> totalDeductByUser = new HashMap<>();

        for (ShopDealerCapital cap : capitals) {
            Integer dealerUserId = cap.getUserId();
            BigDecimal amount = cap.getMoney();
            if (dealerUserId == null || amount == null || amount.signum() <= 0) {
                continue;
            }

            BigDecimal rollbackAmount = amount.multiply(ratio).setScale(2, RoundingMode.HALF_UP);
            if (rollbackAmount.signum() <= 0) {
                continue;
            }

            totalDeductByUser.merge(dealerUserId, rollbackAmount, BigDecimal::add);

            Integer flowType = cap.getFlowType();
            if (flowType != null && flowType == FLOW_TYPE_DELIVERY_REWARD) {
                moneyDeductByUser.merge(dealerUserId, rollbackAmount, BigDecimal::add);
                continue;
            }

            // 佣金收入：若已解冻(有 flowType=50 marker)，则从可提现扣回；否则从冻结扣回
            boolean unfrozen = hasUnfreezeMarker(tenantId, cap);
            if (unfrozen) {
                moneyDeductByUser.merge(dealerUserId, rollbackAmount, BigDecimal::add);
            } else {
                freezeDeductByUser.merge(dealerUserId, rollbackAmount, BigDecimal::add);
            }
        }

        LocalDateTime now = LocalDateTime.now();
        for (Map.Entry<Integer, BigDecimal> entry : totalDeductByUser.entrySet()) {
            Integer dealerUserId = entry.getKey();
            BigDecimal totalDeduct = entry.getValue();
            if (dealerUserId == null || totalDeduct == null || totalDeduct.signum() <= 0) {
                continue;
            }

            BigDecimal freezeDeduct = freezeDeductByUser.getOrDefault(dealerUserId, BigDecimal.ZERO);
            BigDecimal moneyDeduct = moneyDeductByUser.getOrDefault(dealerUserId, BigDecimal.ZERO);

            LambdaUpdateWrapper<ShopDealerUser> uw = new LambdaUpdateWrapper<ShopDealerUser>()
                .eq(ShopDealerUser::getTenantId, tenantId)
                .eq(ShopDealerUser::getUserId, dealerUserId)
                .setSql("total_money = IFNULL(total_money,0) - " + totalDeduct.toPlainString())
                .set(ShopDealerUser::getUpdateTime, now);

            if (freezeDeduct.signum() > 0) {
                uw.setSql("freeze_money = IFNULL(freeze_money,0) - " + freezeDeduct.toPlainString());
            }
            if (moneyDeduct.signum() > 0) {
                uw.setSql("money = IFNULL(money,0) - " + moneyDeduct.toPlainString());
            }

            boolean updated = shopDealerUserService.update(uw);
            if (!updated) {
                log.warn("订单退款扣回分销金额失败：未找到分销账户 - tenantId={}, orderNo={}, dealerUserId={}, totalDeduct={}, freezeDeduct={}, moneyDeduct={}",
                    tenantId, orderNo, dealerUserId, totalDeduct, freezeDeduct, moneyDeduct);
            }
        }

        markDealerOrderInvalid(tenantId, orderNo);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean rollbackOnOrderRefundV2(ShopOrder order, BigDecimal refundAmount) {
        if (order == null || order.getTenantId() == null || StrUtil.isEmpty(order.getOrderNo())) {
            return true;
        }
        Integer tenantId = order.getTenantId();
        String orderNo = order.getOrderNo();

        //判断退款金额不能大于实付金额
        if(refundAmount.compareTo(order.getPayPrice()) > 0){
            throw new RuntimeException("退款金额不能大于订单实付金额！");
        }

        //执行分销订单退款业务
        ShopDealerRefundDto refundDto = new ShopDealerRefundDto();
        refundDto.setOrderNo(orderNo);
        refundDto.setTenantId(tenantId);
        refundDto.setRefundAmount(refundAmount);
        Boolean refundResult = shopDealerUserService.refundOrder(refundDto);

        if(refundResult){
            //退款金额与实付金额一致，标记分销订单失效
            if (order.getPayPrice().compareTo(refundAmount) == 0) {
                markDealerOrderInvalid(tenantId, orderNo);
            }else {
                BigDecimal rate = refundAmount.divide(order.getPayPrice(), 3, RoundingMode.HALF_UP);
                BigDecimal remainRate = BigDecimal.ONE.subtract(rate);
                LambdaQueryWrapper<ShopDealerOrder> orderLambdaQueryWrapper = new LambdaQueryWrapper<ShopDealerOrder>().eq(ShopDealerOrder::getOrderNo, orderNo);
                ShopDealerOrder shopDealerOrder = shopDealerOrderService.getOne(orderLambdaQueryWrapper);
                if(shopDealerOrder != null){
                    if(shopDealerOrder.getFirstMoney().compareTo(BigDecimal.ZERO) > 0){
                        shopDealerOrder.setFirstMoney(shopDealerOrder.getFirstMoney().multiply(remainRate));
                    }
                    if(shopDealerOrder.getSecondMoney().compareTo(BigDecimal.ZERO) > 0){
                        shopDealerOrder.setSecondMoney(shopDealerOrder.getSecondMoney().multiply(remainRate));
                    }
                    if(shopDealerOrder.getFirstDividend().compareTo(BigDecimal.ZERO) > 0){
                        shopDealerOrder.setFirstDividend(shopDealerOrder.getFirstDividend().multiply(remainRate));
                    }
                    if(shopDealerOrder.getSecondDividend().compareTo(BigDecimal.ZERO) > 0){
                        shopDealerOrder.setSecondDividend(shopDealerOrder.getSecondDividend().multiply(remainRate));
                    }
                    shopDealerOrder.setUpdateTime(LocalDateTime.now());
                    shopDealerOrderService.updateById(shopDealerOrder);
                }
            }
            return Boolean.TRUE;
        }else {
            return Boolean.FALSE;
        }
    }

    private boolean hasUnfreezeMarker(Integer tenantId, ShopDealerCapital cap) {
        if (tenantId == null || cap == null || cap.getId() == null || cap.getUserId() == null || cap.getOrderNo() == null) {
            return false;
        }
        String markerComment = buildUnfreezeMarkerComment(cap.getId());
        return shopDealerCapitalService.count(
            new LambdaQueryWrapper<ShopDealerCapital>()
                .eq(ShopDealerCapital::getTenantId, tenantId)
                .eq(ShopDealerCapital::getFlowType, FLOW_TYPE_COMMISSION_UNFREEZE_MARKER)
                .eq(ShopDealerCapital::getUserId, cap.getUserId())
                .eq(ShopDealerCapital::getOrderNo, cap.getOrderNo())
                .eq(ShopDealerCapital::getComments, markerComment)
        ) > 0;
    }

    private String buildUnfreezeMarkerComment(Integer capitalId) {
        return "佣金解冻(capitalId=" + capitalId + ")";
    }

    private BigDecimal resolveRefundRatio(BigDecimal orderBaseAmount, BigDecimal refundAmount) {
        if (refundAmount == null || refundAmount.signum() <= 0) {
            return BigDecimal.ONE;
        }
        if (orderBaseAmount == null || orderBaseAmount.signum() <= 0) {
            return BigDecimal.ONE;
        }
        if (refundAmount.compareTo(orderBaseAmount) >= 0) {
            return BigDecimal.ONE;
        }
        return refundAmount.divide(orderBaseAmount, 3, RoundingMode.HALF_UP);
    }

    private void markDealerOrderInvalid(Integer tenantId, String orderNo) {
        if (tenantId == null || orderNo == null || orderNo.isBlank()) {
            return;
        }
        try {
            shopDealerOrderService.update(
                new LambdaUpdateWrapper<ShopDealerOrder>()
                    .eq(ShopDealerOrder::getTenantId, tenantId)
                    .eq(ShopDealerOrder::getOrderNo, orderNo)
                    .set(ShopDealerOrder::getIsInvalid, 1)
                    .set(ShopDealerOrder::getUpdateTime, LocalDateTime.now())
            );
        } catch (Exception e) {
            log.warn("订单退款标记分销订单失效失败 - tenantId={}, orderNo={}", tenantId, orderNo, e);
        }
    }
}

