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

import com.ruoyi.common.core.domain.BaseValidator;
import com.ruoyi.common.core.domain.ValidateResult;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.ss.device.domain.vo.DeviceVO;
import com.ruoyi.ss.device.service.DeviceService;
import com.ruoyi.ss.device.service.DeviceValidator;
import com.ruoyi.ss.model.domain.enums.ModelTag;
import com.ruoyi.ss.suit.domain.SuitBO;
import com.ruoyi.ss.suit.domain.SuitQuery;
import com.ruoyi.ss.suit.domain.SuitVO;
import com.ruoyi.ss.suit.domain.enums.SuitFeeMode;
import com.ruoyi.ss.suit.domain.enums.SuitFeeType;
import com.ruoyi.ss.suit.service.SuitService;
import com.ruoyi.ss.suit.service.SuitValidator;
import com.ruoyi.system.domain.enums.config.ConfigKey;
import com.ruoyi.system.service.ISysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * 2024/4/26
 *
 * @author wjh
 */
@Service
public class SuitValidatorImpl extends BaseValidator implements SuitValidator {

    @Autowired
    private DeviceValidator deviceValidator;

    @Autowired
    private SuitService suitService;

    @Autowired
    private ISysConfigService sysConfigService;

    @Autowired
    private DeviceService deviceService;

    @Override
    public ValidateResult preLogicDel(List<Long> suitIds) {
        if (CollectionUtils.isEmptyElement(suitIds)) {
            return error("数据不允许为空");
        }
        return success();
    }

    /**
     * APP删除前校验
     *
     * @param ids
     */
    @Override
    public ValidateResult preLogicDelByApp(List<Long> ids) {
        ValidateResult result = this.preLogicDel(ids);
        if (result.isError()) {
            return result;
        }

        if (!this.isBelong(ids, SecurityUtils.getUserId())) {
            return error("您没有权限删除这些套餐");
        }

        return success();
    }

    /**
     * APP创建前校验
     *
     * @param suit
     * @return
     */
    @Override
    public ValidateResult preCreateByApp(SuitBO suit) {
        // 公共校验
        ValidateResult result = this.preCreateOrUpdate(suit);
        if (result.isError()) {
            return result;
        }

        // 设备校验
        if (CollectionUtils.isNotEmptyElement(suit.getDeviceIds()) && !deviceValidator.isMch(suit.getDeviceIds(), SecurityUtils.getUserId())) {
            return error("有设备不属于该用户");
        }

        return success();
    }

    /**
     * APP更新前校验
     *
     * @param suit
     * @return
     */
    @Override
    public ValidateResult preUpdateByApp(SuitBO suit) {
        // 公共校验
        ValidateResult result = this.preCreateOrUpdate(suit);
        if (result.isError()) {
            return result;
        }

        Long userId = SecurityUtils.getUserId();

        // 判断套餐是否属于用户
        if (!this.isBelong(Collections.singletonList(suit.getSuitId()), userId)) {
            return error("您无权修改该套餐");
        }

        // 设备校验
        if (CollectionUtils.isNotEmptyElement(suit.getDeviceIds()) && !deviceValidator.isMch(suit.getDeviceIds(), SecurityUtils.getUserId())) {
            return error("有设备不属于该用户");
        }

        return success();
    }

    /**
     * 判断这些套餐是否是指定用户的
     */
    @Override
    public boolean isBelong(Collection<Long> ids, Long userId) {
        if (CollectionUtils.isEmptyElement(ids) || userId == null) {
            return false;
        }
        SuitQuery query = new SuitQuery();
        query.setSuitIds(new ArrayList<>(ids));
        query.setUserId(userId);
        return suitService.selectCount(query) == ids.size();
    }

    @Override
    public ValidateResult preCreateOrUpdate(SuitBO suit) {
        if (suit == null) {
            return error("参数不允许为空");
        }
        SuitService suitService = SpringUtils.getBean(SuitService.class);
        SuitVO old = suitService.selectSuitBySuitId(suit.getSuitId());

        // 判断设备是否支持电量
        if (SuitFeeType.rechargeCountList().contains(suit.getFeeType()) && CollectionUtils.isNotEmptyElement(suit.getDeviceIds())) {
            List<DeviceVO> deviceList = deviceService.selectByIds(new ArrayList<>(suit.getDeviceIds()));
            List<String> unSupport = new ArrayList<>();
            for (DeviceVO device : deviceList) {
                if (!ModelTag.hasTag(device.getModelTags(), ModelTag.ELE)) {
                    unSupport.add(device.getDeviceNo());
                }
            }
            if (CollectionUtils.isNotEmptyElement(unSupport)) {
                return error("以下设备不支持电量套餐：" + StringUtils.join(unSupport, ","));
            }
        }

        return success();
    }

    @Override
    public void afterCheck(SuitVO vo, SuitVO old) {
        if (vo == null){
            return;
        }

        String feeMode = vo.getFeeMode();
        String feeType = vo.getFeeType();
        List<BigDecimal> gearAmount = vo.getGearAmount();
        List<Integer> gearTime = vo.getGearTime();
        Integer value = vo.getValue() ;
        String timeUnit = vo.getTimeUnit();

        // 判断收费方式是否被允许
        if (SuitFeeMode.SINGLE.getMode().equals(feeMode) && !SuitFeeType.allowSingle().contains(feeType)) {
            throw new ServiceException("该收费模式下，收费方式不被允许");
        }

        // 判断分时电价是否设置
        if (SuitFeeType.timingList().contains(feeType) && (CollectionUtils.isEmptyElement(gearAmount) || CollectionUtils.isEmptyElement(gearTime))) {
            throw new ServiceException("需要配置分时电价");
        }

        // 判断单次购买时长/度是否设置
        if (SuitFeeType.singleList().contains(feeType) && value == null) {
            throw new ServiceException("需要配置单次购买时长/度");
        }

        // 判断时长单位是否设置
        if (SuitFeeType.needConfigTimeUnit().contains(feeType) && timeUnit == null) {
            throw new ServiceException("需要配置时长单位");
        }

        // 若开启最低功率阈值，则需设置最低功率
        if (SuitFeeType.rechargeCountList().contains(feeType)) {
            ServiceUtil.assertion (vo.getEnabledLowPowerClose() != null && vo.getEnabledLowPowerClose() && vo.getLowPower() == null, "最低功率阈值不允许为空");
        }

        // 若开启语音播报，则需要设置播报时机
        if (SuitFeeType.TIME.getType().equals(feeType)) {
            ServiceUtil.assertion(vo.getEnabledVoice() != null && vo.getEnabledVoice() && vo.getVoiceMinutes() == null, "语音播报时机不允许为空");
        }

        // 一次性充值的套餐，价格不允许低于最低服务费
        BigDecimal minService = sysConfigService.getBigDecimal(ConfigKey.RECHARGE_MIN_SERVICE);
        if (SuitFeeType.singleList().contains(feeType)) {
            ServiceUtil.assertion(vo.getPrice() == null, "价格不允许为空");
            ServiceUtil.assertion(vo.getPrice().compareTo(minService) < 0, "价格不允许低于" + minService + "元");
        }

        // 判断押金是否设置
        if (SuitFeeMode.SMART.getMode().equals(feeMode)) {
            ServiceUtil.assertion(vo.getDeposit() == null, "押金不允许为空");
            ServiceUtil.assertion(vo.getDeposit().compareTo(minService) < 0, "押金不允许低于" + minService + "元");

            // 若为智能计时、智能按量，则押金不允许低于价格，且必须为价格的整数倍
            if (SuitFeeType.singleList().contains(feeType)) {
                ServiceUtil.assertion(vo.getDeposit().compareTo(vo.getPrice()) < 0, "押金不允许低于价格");

                // 取模，判断余数
                BigDecimal remainder = vo.getDeposit().remainder(vo.getPrice());
                ServiceUtil.assertion(remainder.compareTo(BigDecimal.ZERO) != 0, "押金必须为价格的整数倍");
            }
        }
    }
}
