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

import com.ruoyi.common.core.domain.BaseValidator;
import com.ruoyi.common.core.domain.ValidateResult;
import com.ruoyi.common.enums.ServiceCode;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.ss.channel.domain.ChannelVO;
import com.ruoyi.ss.device.domain.vo.DeviceVO;
import com.ruoyi.ss.device.service.DeviceService;
import com.ruoyi.ss.model.domain.enums.ModelTag;
import com.ruoyi.ss.risk.domain.RiskQuery;
import com.ruoyi.ss.risk.domain.RiskVO;
import com.ruoyi.ss.risk.domain.enums.RiskType;
import com.ruoyi.ss.risk.service.RiskService;
import com.ruoyi.ss.store.domain.StoreVo;
import com.ruoyi.ss.store.service.StoreValidator;
import com.ruoyi.ss.storeStaff.domain.enums.StoreStaffPermissions;
import com.ruoyi.ss.storeStaff.service.StoreStaffValidator;
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.transactionBill.domain.TransactionBill;
import com.ruoyi.ss.transactionBill.domain.TransactionBillQuery;
import com.ruoyi.ss.transactionBill.domain.bo.RechargeBO;
import com.ruoyi.ss.transactionBill.domain.bo.RechargePayDepositBO;
import com.ruoyi.ss.transactionBill.domain.dto.RechargeDTO;
import com.ruoyi.ss.transactionBill.domain.dto.RechargePayBO;
import com.ruoyi.ss.transactionBill.domain.enums.TransactionBillStatus;
import com.ruoyi.ss.transactionBill.domain.enums.TransactionBillType;
import com.ruoyi.ss.transactionBill.domain.vo.TransactionBillVO;
import com.ruoyi.ss.transactionBill.service.TransactionBillService;
import com.ruoyi.ss.transactionBill.service.TransactionBillValidator;
import com.ruoyi.ss.user.domain.SmUserVO;
import com.ruoyi.ss.user.service.UserValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 2024/4/22
 */
@Service
public class TransactionBillValidatorImpl extends BaseValidator implements TransactionBillValidator {

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private UserValidator userValidator;

    @Autowired
    private StoreValidator storeValidator;

    @Autowired
    private TransactionBillService transactionBillService;

    @Autowired
    private RiskService riskService;

    @Autowired
    private StoreStaffValidator storeStaffValidator;

    @Override
    public ValidateResult preAddOrder(RechargeBO bo) {
        if (bo == null) {
            return error("数据不能为空");
        }

        RechargeDTO dto = bo.getParams();
        SuitVO suit = bo.getSuit();

        // 门店
        StoreVo store = bo.getStore();
        if (store != null) {
            LocalTime now = LocalTime.now();
            if (!storeValidator.isBusinessTime(store, now)) {
                return error(String.format("请在营业时间内使用该设备!%s - %s%s",
                        store.getBusinessTimeStart(),
                        store.getBusinessTimeEnd().isAfter(store.getBusinessTimeStart()) ? "" : "次日",
                        store.getBusinessTimeEnd()));
            }
        }

        // 用户
        SmUserVO user = bo.getUser();
        // 检查用户是否有未支付的智能分时段订单
        if (this.hasUnpaidSmartTimingOrder(user.getUserId())) {
            return error("您有未支付的订单，请先支付后继续");
        }
        // 检查用户是否有正在使用中的智能订单
//        if (this.hasUsingSmartOrder(user.getUserId())) {
//            return error("您有正在使用中的智能订单，请结束后继续");
//        }

        // 检查设备是否符合条件
        DeviceVO device = bo.getDevice();
        if (device == null || device.getDeleted()) {
            return error("当前设备不存在");
        }
        if (StringUtils.isEmpty(device.getMac())) {
            return error("当前设备Mac为空，无法充值");
        }
        if (device.getLimitRechargeTime() != null && LocalDateTime.now().isBefore(device.getLimitRechargeTime())) {
            return error("当前设备被限制充值：" + device.getLimitRechargeReason());
        }

        // 判断设备是否有正在使用中的订单
        TransactionBillQuery query = new TransactionBillQuery();
        query.setDeviceId(device.getDeviceId());
        List<TransactionBillVO> usingBill = transactionBillService.selectUsingBill(query);
        if (CollectionUtils.isNotEmptyElement(usingBill)) {
            // 仅允许正在使用中的用户继续下单
            List<Long> allowUserIds = usingBill.stream().map(TransactionBillVO::getUserId).collect(Collectors.toList());
            ServiceUtil.assertion(!allowUserIds.contains(user.getUserId()), "该设备有正在使用中的订单，暂时无法下单");

            // 不允许续分时段订单
            TransactionBillVO timingBill = usingBill.stream()
                    .filter(bill -> SuitFeeType.timingList().contains(bill.getSuitFeeType()))
                    .findFirst().orElse(null);
            ServiceUtil.assertion(timingBill != null, "当前设备存在正在使用中的分时段订单，无法下单");

            // 仅允许续时长单
            ServiceUtil.assertion(!Objects.equals(suit.getFeeType(), SuitFeeType.TIME.getType()), "当前存在正在使用中的订单，仅允许续时长订单");
        }

        // 商户检查
        SmUserVO mch = bo.getMch();
        if (!userValidator.isUsage(device.getUserId())) {
            return error("当前设备商户不存在或不可用，无法充值，请确认商户账号是否正常");
        }
        // 若商户开启了获取用户手机号，则判断用户是否有手机号
        if (mch.getShowBillMobile() != null && mch.getShowBillMobile() && StringUtils.isBlank(user.getPhonenumber())) {
            return error("当前用户未绑定手机号，无法下单");
        }

        // 套餐检查
        if (suit == null) {
            return error("当前设备套餐不存在");
        }
        List<Long> suitDeviceIds = suit.getDeviceList().stream().map(DeviceVO::getDeviceId).collect(Collectors.toList());   // 套餐应用的设备列表
        if (!suitDeviceIds.contains(device.getDeviceId())) {
            return error("当前设备没有该套餐");
        }
        if (suit.getPrice() == null) {
            return error("当前套餐未配置价格，请联系商户处理");
        }
        if (suit.getPrice().compareTo(dto.getSuitPrice()) != 0) {
            return error("当前套餐价格已发生变化，请重新下单");
        }
        if (SuitFeeMode.SMART.getMode().equals(suit.getFeeMode())) {
            if (suit.getDeposit().compareTo(dto.getSuitDeposit()) != 0) {
                return error("当前套餐押金已发生变化，请重新下单");
            }
        }
        if (!suit.getFeeMode().equals(dto.getSuitFeeMode())) {
            return error("当前套餐收费模式发生变化，请重新下单");
        }
        if (!suit.getFeeType().equals(dto.getSuitFeeType())) {
            return error("当前套餐收费类型发生变化，请重新下单");
        }
        if (SuitFeeType.singleList().contains(suit.getFeeType())) {
            // 一次性收费需要配置时间/度数
            if (suit.getValue() == null) {
                return error("当前套餐未配置时间/电量，请联系商户处理");
            }
            if (SuitFeeType.needConfigTimeUnit().contains(suit.getFeeType()) && suit.getTimeUnit() == null) {
                return error("当前套餐未配置时长单位，请联系商户处理");
            }
        }
        if (!Objects.equals(suit.getValue(), dto.getSuitTime())) {
            return error("当前套餐时间/度数已发生变化，请重新下单");
        }
        if (!Objects.equals(suit.getTimeUnit(), dto.getSuitTimeUnit())) {
            return error("当前套餐时间已发生变化，请重新下单");
        }
        if (!CollectionUtils.equals(suit.getGearAmount(), dto.getSuitGearAmount())) {
            return error("套餐收费方式已发生变化，请重新下单");
        }
        if (!CollectionUtils.equals(suit.getGearTime(), dto.getSuitGearTime())) {
            return error("套餐收费方式已发生变化，请重新下单");
        }

//        if (SuitFeeMode.SMART.getMode().equals(suit.getFeeMode())) {
//            if (device.getExpireTime() != null && device.getExpireTime().isAfter(LocalDateTime.now())) {
//                return error("当前设备还有剩余时长，无法选择智能收费方式下单");
//            }
//            if (DeviceOnlineStatus.ONLINE.getStatus().equals(device.getOnlineStatus())
//                    && device.getSurplusEle() != null
//                    && device.getSurplusEle().compareTo(BigDecimal.ZERO) > 0) {
//                return error("当前设备还有剩余电量，无法选择智能收费方式下单");
//            }
//        }
        return success();
    }

    /**
     * 是否有正在使用中的智能订单
     */
    private boolean hasUsingSmartOrder(Long userId) {
        if (userId == null) {
            return false;
        }
        TransactionBillQuery query = new TransactionBillQuery();
        query.setUserId(userId);
        query.setSuitFeeMode(SuitFeeMode.SMART.getMode());
        List<TransactionBillVO> list = transactionBillService.selectUsingBill(query);
        return CollectionUtils.isNotEmptyElement(list);
    }

    /**
     * 是否有支付中的智能分时段订单
     */
    private boolean hasUnpaidSmartTimingOrder(Long userId) {
        if (userId == null) {
            return false;
        }
        TransactionBillQuery query = new TransactionBillQuery();
        query.setUserId(userId);
        query.setSuitFeeMode(SuitFeeMode.SMART.getMode());
        query.setSuitFeeTypes(SuitFeeType.timingList());
        query.setStatus(TransactionBillStatus.UNPAID.getStatus());
        query.setType(TransactionBillType.RECHARGE.getType());
        return transactionBillService.selectSimpleCount(query) > 0;
    }

    /**
     * 获取订单详情前校验
     *
     * @param billId
     * @param userId
     * @return
     */
    @Override
    public ValidateResult preGetDetailByApp(Long billId, Long userId) {
        if (billId == null || userId == null) {
            return error("参数错误：billId与userId不允许为空");
        }


        return success();
    }

    /**
     * 允许查询订单
     * @param billId
     * @param userId
     * @return
     */
    private boolean allowGet(Long billId, Long userId) {
        TransactionBill bill = transactionBillService.selectSmTransactionBillByBillId(billId);
        if (bill != null ) {
            List<Long> allowUsers = Arrays.asList(bill.getUserId(), bill.getMchId());
            return allowUsers.contains(userId);
        }
        return false;
    }

    /**
     * 能否在线充值
     */
    @Override
    public boolean canRechargeOnline(Long deviceId) {
        DeviceVO device = deviceService.selectById(deviceId);
        if (device == null) {
            return false;
        }
        // 4G和WIFI可以进行在线充值
        return device.getModelTags().contains(ModelTag.FOUR_G.getTag()) || device.getModelTags().contains(ModelTag.WIFI.getTag());
    }

    @Override
    public boolean isMch(TransactionBillVO bill, Long userId) {
        return bill != null && bill.getMchId() != null && bill.getMchId().equals(userId);
    }

    @Override
    public boolean isUser(TransactionBillVO bill, Long userId) {
        return bill != null && bill.getUserId() != null && bill.getUserId().equals(userId);
    }

    @Override
    public ValidateResult
    prePay(RechargePayBO bo) {
        TransactionBillVO order = bo.getOrder();
        if (order == null || order.getBillId() == null) {
            return error("订单不存在");
        }
        if (!TransactionBillStatus.UNPAID.getStatus().equals(order.getStatus())) {
            return error("只能支付未支付的订单");
        }
        if (!TransactionBillType.RECHARGE.getType().equals(order.getType())) {
            return error("只能支付充值订单");
        }
        ChannelVO channel = bo.getChannel();
        if (channel == null) {
            return error("支付渠道不存在");
        }
        if (channel.getEnabled() == null || !channel.getEnabled()) {
            return error("支付渠道暂不可用");
        }
        return success();
    }

    @Override
    public ValidateResult prePayDeposit(RechargePayDepositBO bo) {
        TransactionBillVO order = bo.getOrder();
        if (order == null || order.getBillId() == null) {
            return error("订单不存在");
        }
        if (!TransactionBillStatus.UNPAID_DEPOSIT.getStatus().equals(order.getStatus())) {
            return error("只能支付未支付押金的订单");
        }
        if (!TransactionBillType.RECHARGE.getType().equals(order.getType())) {
            return error("只能支付充值订单");
        }

        ChannelVO channel = bo.getChannel();
        if (channel == null) {
            return error("支付渠道不存在");
        }
        if (channel.getEnabled() == null || !channel.getEnabled()) {
            return error("支付渠道不可用");
        }

        SmUserVO user = bo.getUser();
        if (user == null) {
            return error("用户不存在");
        }

        return success();
    }

    @Override
    public boolean isAgent(TransactionBillVO bill, Long userId) {
        return bill != null && userId != null && Objects.equals(bill.getAgentId(), userId);
    }

    @Override
    public void checkRefundRisk(SmUserVO user) {
        if (user == null || user.getUserId() == null) {
            return;
        }

        // 查询未结束的风控列表
        RiskQuery query = new RiskQuery();
        query.setUserId(user.getUserId());
        query.setContainsType(RiskType.REFUND.getType());
        List<RiskVO> riskList = riskService.selectNotFinishedList(query);

        if (CollectionUtils.isNotEmptyElement(riskList)) {
            RiskVO risk = riskList.get(0);
            ServiceUtil.assertion(risk == null, "风控信息异常");

            LocalDateTime endTime = risk.getEndTime();
            if (endTime == null) {
                throw new ServiceException("您被限制退款：" +  risk.getReason(), ServiceCode.RISK_REFUND.getCode(), risk.getRiskId());
            } else if (endTime.isAfter(LocalDateTime.now())){
                throw new ServiceException("您被限制退款至" + DateUtils.format(endTime, DateUtils.YYYY_MM_DD_HH_MM_SS) + ":" + risk.getReason(), ServiceCode.RISK_REFUND.getCode(), risk.getRiskId());
            }
        }
    }

    @Override
    public boolean canOperaOrder(TransactionBillVO bill, Long userId) {
        if (bill == null || userId == null) {
            return false;
        }
        return this.isMch(bill, userId)
                || this.isAgent(bill, userId)
                || storeStaffValidator.hasStorePermission(bill.getStoreId(), userId, StoreStaffPermissions.ORDER_OPERA);
    }

    @Override
    public boolean canViewOrder(TransactionBillVO bill, Long userId) {
        return this.isMch(bill, userId)
                || this.isUser(bill, userId)
                || this.isAgent(bill, userId)
                || storeStaffValidator.hasStorePermission(bill.getStoreId(), userId, StoreStaffPermissions.ORDER_OPERA);
    }
}
