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

import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.ss.bonus.domain.Bonus;
import com.ruoyi.ss.bonus.domain.BonusVO;
import com.ruoyi.ss.bonus.domain.enums.BonusArrivalType;
import com.ruoyi.ss.bonus.domain.enums.BonusBstType;
import com.ruoyi.ss.bonus.domain.enums.BonusStatus;
import com.ruoyi.ss.bonus.service.BonusConverter;
import com.ruoyi.ss.bonus.service.BonusService;
import com.ruoyi.ss.channel.domain.enums.ChannelType;
import com.ruoyi.ss.device.domain.enums.DeviceServiceMode;
import com.ruoyi.ss.device.domain.vo.DeviceVO;
import com.ruoyi.ss.device.service.DeviceAssembler;
import com.ruoyi.ss.storeStaff.domain.StoreStaffVO;
import com.ruoyi.ss.storeStaff.service.StoreStaffService;
import com.ruoyi.ss.transactionBill.domain.vo.TransactionBillVO;
import com.ruoyi.ss.user.domain.SmUserVO;
import com.ruoyi.ss.user.service.UserService;
import com.ruoyi.ss.vipOrder.domain.VipOrderVO;
import com.ruoyi.system.service.ISysDeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author wjh
 * 2024/8/20
 */
@Service
public class BonusConverterImpl implements BonusConverter {

    @Autowired
    private DeviceAssembler deviceAssembler;

    @Autowired
    private ISysDeptService deptService;

    @Autowired
    private StoreStaffService storeStaffService;

    @Autowired
    private BonusService bonusService;

    @Autowired
    private UserService userService;


    @Override
    public List<Bonus> toPoList(SysDept platform, DeviceVO device, List<StoreStaffVO> staffList) {
        List<Bonus> result = new ArrayList<>();
        if (platform == null || device == null) {
            return result;
        }
        // 剩余可分配的分成比例
        BigDecimal point = BigDecimal.valueOf(100);

        // 直营模式
        if (DeviceServiceMode.DIRECT.getMode().equals(device.getServiceMode())) {
            // 拼接设备服务费费率
            deviceAssembler.assembleRealServiceRate(device);

            // 按照百分比收取服务费
            BigDecimal serviceRate = device.getRealServiceRate();   // 服务费比例
            Bonus platformBonus = this.toPo(platform, serviceRate);
            result.add(platformBonus);
            point = point.subtract(serviceRate);
        }
        // 代理模式
        else if (DeviceServiceMode.AGENT.getMode().equals(device.getServiceMode())) {
            // 平台收取代理商的服务费
            BigDecimal platformAgentServiceRate = device.getAgentUserServiceRate() == null ? BigDecimal.ZERO : device.getAgentUserServiceRate();
            // 代理商给商户设备设置的服务费
            BigDecimal agentMchServiceRate = device.getAgentServiceRate() == null ? BigDecimal.ZERO : device.getAgentServiceRate();

            // 添加平台服务费
            Bonus platformBonus = this.toPo(platform, platformAgentServiceRate);
            result.add(platformBonus);
            point = point.subtract(platformAgentServiceRate);

            // 添加代理服务费
            // 代理商收取服务费 = 代理商给商户的服务费 - 平台收取代理商的服务费
            if (device.getAgentId() != null) {
                BigDecimal agentArrivalPoint = agentMchServiceRate.subtract(platformAgentServiceRate);
                Bonus agentBonus = this.toPo(device.getAgentId(), device.getAgentName(), agentArrivalPoint, device.getAgentId().toString(), BonusArrivalType.AGENT);
                if (agentBonus != null) {
                    result.add(agentBonus);
                    point = point.subtract(agentArrivalPoint);
                }
            }
        }

        // 若有员工，则判断是否有分成
        if (CollectionUtils.isNotEmptyElement(staffList)) {
            for (StoreStaffVO staff : staffList) {
                if (staff == null || staff.getPoint().compareTo(BigDecimal.ZERO) == 0 || staff.getEnabled() == null || !staff.getEnabled()) {
                    continue;
                }

                Bonus staffBonus = this.toPo(staff);
                if (staffBonus != null) {
                    result.add(staffBonus);
                    point = point.subtract(staffBonus.getPoint());
                }
            }
        }

        // 剩余的给商户
        String ancestors = Stream.of(device.getAgentId(), device.getUserId())
                .filter(Objects::nonNull)
                .map(Object::toString)
                .collect(Collectors.joining(","));
        Bonus mchBonus = this.toPo(device.getUserId(), device.getUserName(), point, ancestors, BonusArrivalType.MCH);
        this.addBonus(result, mchBonus);

        return result;
    }

    private Bonus toPo(StoreStaffVO staff) {
        String staffAncestors = Stream.of(staff.getMchId(), staff.getUserId())
                .filter(Objects::nonNull)
                .map(Object::toString)
                .collect(Collectors.joining(","));
        return this.toPo(staff.getUserId(), staff.getUserName(), staff.getPoint(), staffAncestors, BonusArrivalType.STAFF);
    }

    @Override
    public List<Bonus> toPoList(VipOrderVO order) {
        if (order == null) {
            return Collections.emptyList();
        }
        SmUserVO mch = userService.selectSmUserByUserId(order.getMchId());
        SysDept platform = deptService.selectDeptById(Constants.ROOT_DEPT);
        if (mch == null || platform == null) {
            return Collections.emptyList();
        }
        // 渠道类型
        String channelType = order.getChannelType();

        List<Bonus> result = new ArrayList<>();

        // 是否平台收取
        boolean isPlatform = ChannelType.PLATFORM.getType().equals(channelType);
        // 平台收取
        if (isPlatform && mch.getServiceRate() != null) {
            this.addBonus(result, toPo(platform, mch.getRealServiceRate()));
        }

        // 员工收取
        List<StoreStaffVO> staffList = storeStaffService.selectByStoreId(order.getLevelStoreId());
        if (CollectionUtils.isNotEmptyElement(staffList)) {
            for (StoreStaffVO staff : staffList) {
                this.addBonus(result, toPo(staff));
            }
        }

        // 最后商户收取
        BigDecimal totalPoint = CollectionUtils.sumDecimal(result, Bonus::getPoint);
        BigDecimal mchPoint = new BigDecimal("100").subtract(totalPoint);
        Bonus mchBonus = toPo(mch.getUserId(), mch.getRealOrUserName(), mchPoint, "", BonusArrivalType.MCH);
        this.addBonus(result, mchBonus);

        // 带上业务数据
        for (Bonus bonus : result) {
            bonus.setBstType(BonusBstType.VIP.getType());
            bonus.setBillId(order.getId());
            bonus.setBillNo(order.getOrderNo());
            bonus.setToBalance(isPlatform);
        }

        // 分钱
        bonusService.partBonus(result, order.getAmount());

        return result;
    }

    @Override
    public List<Bonus> toPoList(DeviceVO device, TransactionBillVO bill, String channelType) {
        // 只有通过平台渠道支付的才需要分成给余额
        if (ChannelType.PLATFORM.getType().equals(channelType)) {
            // 获取设备分成数据
            deviceAssembler.assembleBonusList(device);
            // 构造分成列表
            return this.buildBonusListByPlatform(device.getBonusList(), bill);
        }
        // 其他只需要记录分成数据即可
        else {
            return this.buildBonusListByCustom(bill);
        }
    }


    public List<Bonus> buildBonusListByPlatform(List<Bonus> bonusList, TransactionBillVO bill) {
        // 设置分成基础数据
        for (Bonus bonus : bonusList) {
            bonus.setBstType(BonusBstType.RECHARGE.getType());
            bonus.setBillId(bill.getBillId());
            bonus.setBillNo(bill.getBillNo());
            bonus.setToBalance(true);
        }
        // 计算分成金额
        bonusService.partBonus(bonusList, bill.getMoney());

        return bonusList;
    }


    public List<Bonus> buildBonusListByCustom(TransactionBillVO bill) {
        List<Bonus> bonusList = new ArrayList<>();
        Bonus bonus = new BonusVO();
        bonus.setBstType(BonusBstType.RECHARGE.getType());
        bonus.setBillId(bill.getBillId());
        bonus.setBillNo(bill.getBillNo());
        bonus.setStatus(BonusStatus.DIVIDEND.getStatus());
        bonus.setArrivalId(bill.getMchId());
        bonus.setArrivalName(bill.getMchName());
        bonus.setArrivalType(BonusArrivalType.MCH.getType());
        bonus.setPoint(BigDecimal.valueOf(100));
        bonus.setAmount(bill.getMoney());
        bonus.setRefundAmount(BigDecimal.ZERO);
        bonus.setAncestors(String.valueOf(bill.getMchId()));
        bonus.setDeptId(null);
        bonus.setPayTime(LocalDateTime.now());
        bonus.setPrePayTime(LocalDateTime.now());
        bonus.setPayedAmount(bill.getMoney());
        bonus.setWaitAmount(BigDecimal.ZERO);
        bonus.setToBalance(false);
        bonusList.add(bonus);
        return bonusList;
    }

    private void addBonus(List<Bonus> list, Bonus po) {
        if (po == null) {
            return;
        }
        list.add(po);
    }

    private Bonus toPo(SysDept dept, BigDecimal point) {
        if (dept == null) {
            return null;
        }
        if (point == null) {
            point = BigDecimal.ZERO;
        }

        Bonus po = new Bonus();
        po.setStatus(BonusStatus.UN_DIVIDEND.getStatus());
        po.setArrivalId(dept.getDeptId());
        po.setArrivalName(dept.getDeptName());
        BonusArrivalType arrivalType = BonusArrivalType.parseByDept(dept);
        if (arrivalType != null) {
            po.setArrivalType(arrivalType.getType());
        }
        po.setPoint(point);
        po.setAncestors(dept.getAncestors());
        po.setDeptId(dept.getDeptId());

        return po;
    }

    private Bonus toPo(Long userId, String userName, BigDecimal point, String ancestors, BonusArrivalType arrivalType) {
        if (userId == null || point == null || point.compareTo(BigDecimal.ZERO) < 0 || point.compareTo(new BigDecimal(100)) > 0) {
            return null;
        }

        Bonus po = new Bonus();
        po.setStatus(BonusStatus.UN_DIVIDEND.getStatus());
        po.setArrivalId(userId);
        po.setArrivalName(userName);
        po.setArrivalType(arrivalType.getType());
        po.setPoint(point);
        po.setAncestors(ancestors);
        po.setDeptId(Constants.ROOT_DEPT);

        return po;
    }
}
