package com.ruoyi.bst.bonus.service.impl;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import com.github.pagehelper.PageHelper;
import com.ruoyi.bst.area.service.AreaService;
import com.ruoyi.bst.areaJoin.domain.AreaJoinVO;
import com.ruoyi.bst.areaJoin.domain.enums.AreaJoinType;
import com.ruoyi.bst.areaJoin.service.AreaJoinService;
import com.ruoyi.bst.balanceLog.domain.enums.BalanceLogBstType;
import com.ruoyi.bst.bonus.domain.Bonus;
import com.ruoyi.bst.bonus.domain.BonusQuery;
import com.ruoyi.bst.bonus.domain.BonusVO;
import com.ruoyi.bst.bonus.domain.enums.BonusArrivalType;
import com.ruoyi.bst.bonus.domain.enums.BonusBstType;
import com.ruoyi.bst.bonus.domain.enums.BonusStatus;
import com.ruoyi.bst.bonus.mapper.BonusMapper;
import com.ruoyi.bst.bonus.service.BonusConverter;
import com.ruoyi.bst.bonus.service.BonusService;
import com.ruoyi.bst.bonus.utils.BonusUtil;
import com.ruoyi.bst.bonusRefund.domain.BonusRefund;
import com.ruoyi.bst.bonusRefund.service.BonusRefundConverter;
import com.ruoyi.bst.bonusRefund.service.BonusRefundService;
import com.ruoyi.bst.device.domain.DeviceVO;
import com.ruoyi.bst.device.service.DeviceService;
import com.ruoyi.common.core.domain.vo.UserVO;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.system.user.service.UserService;

import lombok.extern.slf4j.Slf4j;

/**
 * 分成明细Service业务层处理
 *
 * @author ruoyi
 * @date 2025-03-26
 */
@Service
@Slf4j
public class BonusServiceImpl implements BonusService {
    @Autowired
    private BonusMapper bonusMapper;

    @Autowired
    private ScheduledExecutorService scheduledExecutorService;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private UserService userService;

    @Autowired
    private BonusRefundService bonusRefundService;

    @Autowired
    private BonusRefundConverter bonusRefundConverter;

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private AreaService areaService;

    @Autowired
    private AreaJoinService areaJoinService;

    @Autowired
    private BonusConverter bonusConverter;

    /**
     * 查询分成明细
     *
     * @param id 分成明细主键
     * @return 分成明细
     */
    @Override
    public BonusVO selectBonusById(Long id, boolean scope) {
        if (id == null) {
            return null;
        }
        BonusQuery query = new BonusQuery();
        query.setId(id);
        query.setScope(scope);
        return this.selectOne(query);
    }

    private BonusVO selectOne(BonusQuery query) {
        PageHelper.startPage(1, 1);
        List<BonusVO> list = this.selectBonusList(query);
        return CollectionUtils.firstElement(list);
    }

    /**
     * 查询分成明细列表
     *
     * @param bonus 分成明细
     * @return 分成明细
     */
    @Override
    public List<BonusVO> selectBonusList(BonusQuery bonus) {
        return bonusMapper.selectBonusList(bonus);
    }

    /**
     * 新增分成明细
     *
     * @param bonus 分成明细
     * @return 结果
     */
    @Override
    public int insertBonus(Bonus bonus) {
        bonus.setCreateTime(DateUtils.getNowDate());
        return bonusMapper.insertBonus(bonus);
    }

    /**
     * 修改分成明细
     *
     * @param bonus 分成明细
     * @return 结果
     */
    @Override
    public int updateBonus(Bonus bonus) {
        return bonusMapper.updateBonus(bonus);
    }

    /**
     * 批量删除分成明细
     *
     * @param ids 需要删除的分成明细主键
     * @return 结果
     */
    @Override
    public int deleteBonusByIds(Long[] ids) {
        return bonusMapper.deleteBonusByIds(ids);
    }

    /**
     * 删除分成明细信息
     *
     * @param id 分成明细主键
     * @return 结果
     */
    @Override
    public int deleteBonusById(Long id) {
        return bonusMapper.deleteBonusById(id);
    }

    @Override
    public int batchInsert(List<? extends Bonus> list) {
        if (CollectionUtils.isEmpty(list)) {
            return 0;
        }
        Date now = DateUtils.getNowDate();
        list.forEach(bonus -> {
            bonus.setCreateTime(now);
        });
        return bonusMapper.batchInsert(list);
    }

    @Override
    public boolean validByBst(BonusBstType bstType, Long bstId) {
        if (bstType == null || bstId == null) {
            return false;
        }
        bonusMapper.validByBst(bstType.getType(), bstId);
        return true;
    }

    @Override
    public boolean prepayByBst(BonusBstType bstType, Long bstId, BigDecimal totalAmount, LocalDateTime waitTime) {
        if (bstType == null || bstId == null) {
            return false;
        }

        // 查询分成列表
        BonusQuery query = new BonusQuery();
        query.setBstType(bstType.getType());
        query.setBstId(bstId);
        List<BonusVO> list = this.selectBonusList(query);
        int rows = prepay(list, totalAmount, waitTime);
        return rows == list.size();
    }

    // 预分成
    private int prepay(List<BonusVO> list, BigDecimal totalAmount, LocalDateTime waitTime) {
        if (CollectionUtils.isEmptyElement(list)) {
            return 0;
        }

        // 计算分成金额
        BonusUtil.partAmount(list, totalAmount);

        // 获取用户列表
        List<UserVO> userList = userService.selectByIds(list.stream()
                .filter(item -> BonusArrivalType.userList().contains(item.getArrivalType()))
                .map(Bonus::getArrivalId)
                .collect(Collectors.toList()));

        LocalDateTime now = LocalDateTime.now();
        for (BonusVO bonus : list) {
            bonus.setWaitAmount(bonus.getAmount());
            bonus.setWaitTime(waitTime);
            // 设置预计分成时间
            if (BonusArrivalType.userList().contains(bonus.getArrivalType())) {
                UserVO user = userList.stream().filter(item -> item.getUserId().equals(bonus.getArrivalId()))
                        .findFirst().orElse(null);
                if (user == null) {
                    continue;
                }
                bonus.setPrePayTime(now.plusHours(user.getBonusDelay()));
            } else {
                bonus.setPrePayTime(now);
            }
        }

        // 更新数据库
        Integer result = transactionTemplate.execute(status -> {
            int rows = bonusMapper.prepay(list);
            ServiceUtil.assertion(rows != list.size(), "预分成失败，请刷新后重试");
            return rows;
        });

        // 如果预分成成功，则立即执行一次分成
        if (result != null && result > 0) {
            scheduledExecutorService.schedule(() -> {
                this.payBonusBeforeTime(LocalDateTime.now());
            }, 3, TimeUnit.SECONDS);
        }

        return result == null ? 0 : result;
    }

    @Override
    public int payBonusBeforeTime(LocalDateTime time) {
        // 查询预计分成时间当前时间之前，且为待分成的分成单
        BonusQuery query = new BonusQuery();
        query.setStatus(BonusStatus.WAIT_DIVIDE.getStatus());
        query.setPrePayTimeEnd(time);
        List<BonusVO> list = this.selectBonusList(query);

        if (CollectionUtils.isEmptyElement(list)) {
            log.info("暂无待分成的分成单");
            return 0;
        }

        int sum = 0;
        for (BonusVO bonus : list) {
            try {
                sum += this.payBonus(bonus);
            } catch (Exception e) {
                log.warn("分成打款失败：id={}, e={}", bonus.getId(), e.getMessage());
            }
        }

        return sum;
    }

    @Override
    public int payBonus(BonusVO bonus) {
        ServiceUtil.assertion(bonus == null, "待打款的分成不存在");
        ServiceUtil.assertion(!BonusStatus.canPay().contains(bonus.getStatus()), "ID为%s的分成当前状态不允许打款", bonus.getId());

        Integer result = transactionTemplate.execute(status -> {
            // 更新分成状态为已分成
            int pay = bonusMapper.pay(bonus.getId(), bonus.getWaitAmount(), LocalDateTime.now());
            ServiceUtil.assertion(pay != 1, "分成打款失败，待分金额不足或状态已改变");

            // 若需要打款到余额，根据类型，添加金额
            if (bonus.getToBalance() != null && bonus.getToBalance()) {
                if (BonusArrivalType.userList().contains(bonus.getArrivalType())) {
                    BalanceLogBstType bstType = BalanceLogBstType.parseByBonusBstType(bonus.getBstType());
                    int add = userService.addBalance(bonus.getArrivalId(), bonus.getWaitAmount(), bstType,
                            bonus.getBstId(), bonus.getReason());
                    ServiceUtil.assertion(add != 1, "为用户%s增加账户金额失败", bonus.getArrivalId());
                }
            }

            return pay;
        });

        return result == null ? 0 : result;
    }

    @Override
    public int payBonus(Long id) {
        if (id == null) {
            return 0;
        }
        BonusVO bonus = this.selectBonusById(id);
        return this.payBonus(bonus);
    }

    @Override
    public boolean refundByBst(BonusBstType bstType, Long bstId, BigDecimal refundAmount, String reason) {
        if (bstType == null || bstId == null || refundAmount == null) {
            return false;
        }
        // 查询分成列表
        BonusQuery query = new BonusQuery();
        query.setBstType(bstType.getType());
        query.setBstId(bstId);
        List<BonusVO> list = this.selectBonusList(query);
        if (CollectionUtils.isEmptyElement(list)) {
            return false;
        }

        // 退款
        return this.refund(list, refundAmount, reason);
    }

    /**
     * 分成退款
     *
     * @param bonusList
     * @param refundAmount
     * @param reason
     * @return
     */
    private boolean refund(List<BonusVO> bonusList, BigDecimal refundAmount, String reason) {
        if (CollectionUtils.isEmptyElement(bonusList)) {
            return true;
        }
        if (refundAmount == null) {
            return false;
        }

        // 构建退款列表
        List<Bonus> refundList = BonusUtil.buildRefundList(bonusList, refundAmount);
        ServiceUtil.assertion(CollectionUtils.isEmptyElement(refundList), "退款金额分配出错");

        // 执行退款逻辑
        Boolean result = transactionTemplate.execute(status -> {
            int update = 0;

            // 分成退款
            for (Bonus bonus : refundList) {
                Long id = bonus.getId();
                BigDecimal amount = bonus.getRefundAmount();
                ServiceUtil.assertion(id == null, "ID不允许为空");
                ServiceUtil.assertion(amount.compareTo(BigDecimal.ZERO) < 0, "退款金额必须大于0");
                int refund = 0;
                if (BonusStatus.INVALID.getStatus().equals(bonus.getStatus())) {
                    refund = bonusMapper.refundWhenInvalid(id, amount);
                    ServiceUtil.assertion(refund != 1, "未出账ID为%s的分成可退款金额不足%s元", id, amount);
                } else if (BonusStatus.WAIT_DIVIDE.getStatus().equals(bonus.getStatus())) {
                    refund = bonusMapper.refundWhenWaitDivide(id, amount);
                    ServiceUtil.assertion(refund != 1, "待分成ID为%s的分成可退款金额不足%s元", id, amount);
                } else if (BonusStatus.DIVIDEND.getStatus().equals(bonus.getStatus())) {
                    refund = bonusMapper.refundWhenDividend(id, amount);
                    ServiceUtil.assertion(refund != 1, "已分成ID为%s的分成可退款金额不足%s元", id, amount);

                    if (bonus.getToBalance() != null && bonus.getToBalance()
                            && BonusArrivalType.userList().contains(bonus.getArrivalType())) {
                        int subtract = userService.subtractBalance(
                                bonus.getArrivalId(),
                                bonus.getRefundAmount(),
                                BalanceLogBstType.parseByBonusBstType(bonus.getBstType()),
                                bonus.getBstId(),
                                reason,
                                true);
                        ServiceUtil.assertion(subtract != 1, "用户【%s】余额不足%s元，", bonus.getArrivalName(), amount);
                    }
                }

                update += refund;
            }
            ServiceUtil.assertion(refundList.size() != update, "退款失败");

            // 创建分成退款记录
            List<BonusRefund> bonusRefundList = bonusRefundConverter.toPo(refundList);
            int insertBonusRefund = bonusRefundService.batchInsert(bonusRefundList);
            ServiceUtil.assertion(insertBonusRefund != bonusRefundList.size(), "创建分成退款记录失败");

            return true;
        });

        return result != null && result;
    }

    @Override
    public List<Bonus> preview(Long deviceId) {
        if (deviceId == null) {
            return Collections.emptyList();
        }
        // 查询设备信息
        DeviceVO device = deviceService.selectDeviceById(deviceId);
        if (device == null) {
            return Collections.emptyList();
        }

        // 查询设备所属区域合伙人
        List<AreaJoinVO> partners = areaJoinService.selectListByAreaId(device.getAreaId(),
                AreaJoinType.PARTNER.getCode());

        // 查询设备所属区域加盟商
        AreaJoinVO join = areaJoinService.selectByUserArea(device.getMchId(), device.getAreaId());

        return bonusConverter.toBaseBonusListPlatform(device, partners, join, true);
    }
}
