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.DateUtils;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.ss.bonus.domain.Bonus;
import com.ruoyi.ss.bonus.domain.enums.BonusArrivalType;
import com.ruoyi.ss.bonus.domain.enums.BonusStatus;
import com.ruoyi.ss.bonus.service.BonusConverter;
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.transactionBill.domain.vo.TransactionBillVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
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;


    @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;
                }
                String staffAncestors = Stream.of(device.getUserId(), staff.getUserId())
                        .filter(Objects::nonNull)
                        .map(Object::toString)
                        .collect(Collectors.joining(","));
                Bonus staffBonus = this.toPo(staff.getUserId(), staff.getUserName(), staff.getPoint(), staffAncestors, BonusArrivalType.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);
        if (mchBonus != null) {
            result.add(mchBonus);
        }

        return result;
    }

    @Override
    public List<Bonus> toPo(TransactionBillVO bill) {
        if (bill == null) {
            return Collections.emptyList();
        }
        LocalDateTime payTime = DateUtils.toLocalDateTime(bill.getPayTime());

        List<Bonus> result = new ArrayList<>();
        BigDecimal decimal100 = new BigDecimal("100");

        // TODO 平台
        // 平台百分比
        BigDecimal platformPoint = bill.getServiceCharge().multiply(decimal100).divide(bill.getMoney(), 2, RoundingMode.HALF_UP);
        Bonus platformBonus = new Bonus();
        platformBonus.setBillId(bill.getBillId());
        platformBonus.setBillNo(bill.getBillNo());
        platformBonus.setStatus(BonusStatus.DIVIDEND.getStatus());
        platformBonus.setArrivalId(Constants.ROOT_DEPT);
        platformBonus.setArrivalName("创特科技");
        platformBonus.setArrivalType(BonusArrivalType.PLATFORM.getType());
        platformBonus.setPoint(platformPoint);
        platformBonus.setAmount(bill.getServiceCharge());
        platformBonus.setRefundAmount(bill.getRefundServiceAmount());
        platformBonus.setAncestors("");
        platformBonus.setDeptId(Constants.ROOT_DEPT);
        platformBonus.setPayTime(payTime);
        platformBonus.setPrePayTime(payTime);
        platformBonus.setPayedAmount(bill.getServiceCharge().subtract(bill.getRefundServiceAmount()));
        platformBonus.setWaitAmount(BigDecimal.ZERO);
        result.add(platformBonus);

        // TODO 商户
        // 商户百分比
        BigDecimal mchPoint = decimal100.subtract(platformPoint);
        Bonus mchBonus = new Bonus();
        mchBonus.setBillId(bill.getBillId());
        mchBonus.setBillNo(bill.getBillNo());
        mchBonus.setStatus(BonusStatus.DIVIDEND.getStatus());
        mchBonus.setArrivalId(bill.getMchId());
        mchBonus.setArrivalName(bill.getMchName());
        mchBonus.setArrivalType(BonusArrivalType.MCH.getType());
        mchBonus.setPoint(mchPoint);
        mchBonus.setAmount(bill.getArrivalAmount());
        mchBonus.setRefundAmount(bill.getRefundMchAmount());
        mchBonus.setAncestors(bill.getMchId().toString());
        mchBonus.setDeptId(Constants.ROOT_DEPT);
        mchBonus.setPayTime(payTime);
        mchBonus.setPrePayTime(payTime);
        mchBonus.setPayedAmount(bill.getArrivalAmount().subtract(bill.getRefundMchAmount()));
        mchBonus.setWaitAmount(BigDecimal.ZERO);
        result.add(mchBonus);

        return result;
    }

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

        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;
    }
}
