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

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.constant.ServiceConstants;
import com.ruoyi.common.core.domain.BaseValidator;
import com.ruoyi.common.core.domain.ValidateResult;
import com.ruoyi.common.core.domain.entity.User;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.ss.feeRule.domain.FeeRuleVO;
import com.ruoyi.ss.feeRule.service.IFeeRuleService;
import com.ruoyi.ss.order.domain.Order;
import com.ruoyi.ss.order.domain.OrderBO;
import com.ruoyi.ss.order.domain.OrderQuery;
import com.ruoyi.ss.order.domain.OrderVO;
import com.ruoyi.ss.order.domain.dto.OrderDTO;
import com.ruoyi.ss.order.domain.vo.ReservedTimePeriod;
import com.ruoyi.ss.order.mapper.OrderMapper;
import com.ruoyi.ss.order.service.IOrderService;
import com.ruoyi.ss.order.service.IOrderValidator;
import com.ruoyi.ss.room.domain.RoomVO;
import com.ruoyi.ss.room.service.IRoomService;
import com.ruoyi.ss.store.domain.StoreVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import static com.ruoyi.common.constant.ServiceConstants.ORDER_TYPE_RESERVE;
import static com.ruoyi.common.constant.ServiceConstants.ROOM_STATUS_FREE;

@Service
public class IOrderValidatorImpl extends BaseValidator implements IOrderValidator {

    @Autowired
    private IOrderService orderService;

    @Resource
    private OrderMapper orderMapper;

    @Autowired
    private IOrderValidator orderValidator;

    @Autowired
    private IRoomService roomService;

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

        FeeRuleVO rule = bo.getFeeRule();
        LocalTime reserveTime;
        if(ORDER_TYPE_RESERVE.equals(bo.getReType())){
            reserveTime = getReserveTime(bo);
        }else{
            OrderVO originalOrder = bo.getOriginalOrder();
            Date reserveEndTime = originalOrder.getReserveEndTime();
            reserveTime = DateUtils.toLocalTime(reserveEndTime);
        }

        if(rule.getIsRestriction()){
            LocalTime useTimeStart = rule.getUseTimeStart();
            LocalTime useTimeEnd = rule.getUseTimeEnd();
            if (useTimeStart == null || useTimeEnd == null) {
                return error("使用时间不能为空");
            }

            if (!isStoreOpen(useTimeStart,useTimeEnd,reserveTime)) {
                return error("套餐不在使用时间内");
            }
        }

        // 营业时间判断
        StoreVO store = bo.getStore();
        LocalTime businessTimeStart = store.getBusinessTimeStart();
        LocalTime businessTimeEnd = store.getBusinessTimeEnd();
        if (businessTimeStart == null || businessTimeEnd == null) {
            return error("营业时间为空");
        }

        if (ORDER_TYPE_RESERVE.equals(bo.getReType()) && !isStoreOpen(businessTimeStart,businessTimeEnd,reserveTime)) {
            return error("不在营业时间内");
        }

        // 房间还有进行中的订单
        RoomVO room = bo.getRoom();
//        isOverlap
//        boolean inProgressOrder = getInProgressOrder(room.getRoomId());
//        if (inProgressOrder && ServiceConstants.ORDER_TYPE_RESERVE.equals(bo.getReType())) {
//            return error("该房间还有进行中的订单");
//        }

        // 查找包含目标房间ID的订单
//        Optional<OrderVO> roomOrderOptional = inProgressOrder.stream()
//                .filter(orderVO -> orderVO.getRoomId().equals(eRoomVO.getRoomId()))
//                .findFirst();



        if(ServiceConstants.ROOM_TYPE2_PRIVATE_ROOM.equals(room.getType2()) && !ROOM_STATUS_FREE.equals(room.getStatus())){
            return error("该房间非空闲状态");
        }

        FeeRuleVO feeRule = bo.getFeeRule();
        if(!room.getRuleIds().contains(feeRule.getRuleId())){
            return error(StrUtil.format("该房间【{}】没有应用该套餐【{}】",room.getRoomName(),feeRule.getExplain()));
        }

        // 该房间在预约时段是否在订单
        if(bo.getType().equals(ServiceConstants.ORDER_TYPE_RESERVE)){
            // 价格已发生变化
            if(feeRule.getPrice().compareTo(bo.getParams().getPrice()) != 0){
                return error("价格已发生变化");
            }
            // 价格未配置
            if(ObjectUtil.isNull(feeRule.getPrice()) || feeRule.getPrice().compareTo(BigDecimal.ZERO) == 0){
                return error("价格未配置");
            }
            // 小时未配置
            if(ServiceConstants.CHARGE_MODE_CUSTOM_TEMPLATE.equals(feeRule.getMode()) && (ObjectUtil.isNull(feeRule.getHours()) || feeRule.getHours() <= 0)){
                return error("小时未配置");
            }
        }
        return success();
    }

    @Override
    public ValidateResult preOpenDoor(Long roomId, String orderNo) {
        OrderVO orderVO = orderMapper.selectRlOrderByOrderNo(orderNo);

        if(orderVO == null){
            return error("订单不存在");
        }

        if(ServiceConstants.ORDER_STATUS_IN_USE.equals(orderVO.getStatus())){
            return error("订单不在使用中");
        }

        Boolean inTime = DateUtils.isInTime(orderVO.getReserveStartTime(), orderVO.getReserveEndTime());
        if(!inTime){
            return error("不在预约时段");
        }

        return success();
    }

    private static LocalTime getReserveTime(OrderBO bo) {
        OrderDTO params = bo.getParams();
        Date reserveStartTime = params.getReserveStartTime();
        // 将Instant与系统默认时区关联，并转换为LocalDateTime
        return reserveStartTime.toInstant().atZone(ZoneId.systemDefault()).toLocalTime();
    }

    @Override
    public ValidateResult afterAddOrder(Order order) {
        if(isReserved(order.getRoomId(), order.getReserveStartTime(), order.getReserveEndTime()) > 0){
            return error("该房间在预约时段存在订单");
        }
        return success();
    }


    public boolean isStoreOpen(LocalTime startTime, LocalTime endTime,LocalTime reserveTime) {

        // 判断营业时间是否为空
        if (startTime == null || endTime == null) {
            return false; // 或者抛出异常，根据业务需求
        }

        // 判断是否跨天  预定
        if (startTime.isBefore(endTime)) {
            // 不跨天，直接判断当前时间是否在营业时间内
            return !reserveTime.isBefore(startTime) && !reserveTime.isAfter(endTime);
        } else {
            // 跨天，判断当前时间是否在 startTime 到 23:59:59 或者 00:00:00 到 endTime 之间
            return !reserveTime.isBefore(startTime) || !reserveTime.isAfter(endTime);
        }
    }



    @Override
    public void validateChangeRoom(OrderQuery orderQuery) {
        if(StrUtil.isBlank(orderQuery.getOrderNo())){
            throw new ServiceException("订单号不能为空");
        }
        if(orderQuery.getNewRoomId() == null){
            throw new ServiceException("新包间id不能为空");
        }
        OrderVO orderVO = orderService.selectRlOrderByOrderNo(orderQuery.getOrderNo());
        ServiceUtil.assertion(orderVO == null, "订单不存在");
        ServiceUtil.assertion(orderVO.getPaid() == null || orderVO.getPaid().equals(ServiceConstants.ORDER_PAY_STATUS_NON_PAYMENT), "订单未支付");
        ServiceUtil.assertion(orderVO.getStatus() == null || !orderVO.getStatus().equals(ServiceConstants.ORDER_STATUS_PAYMENT_SUCCESS), "订单使用状态");

        RoomVO newRoom = roomService.selectERoomByRoomId(orderQuery.getNewRoomId());
        ServiceUtil.assertion(newRoom == null, "新包间不存在");
        ServiceUtil.assertion(newRoom.getStoreId() == null || !newRoom.getStoreId().equals(orderVO.getStoreId()), "新包间不属于当前店铺，不能更换");
        ServiceUtil.assertion(newRoom.getStatus() == null || !newRoom.getStatus().equals(ServiceConstants.ROOM_STATUS_FREE), "新包间非空闲状态，不能更换");
        ServiceUtil.assertion(newRoom.getType() == null || !newRoom.getType().equals(orderVO.getRoomType()), "新包间类型与原包间类型不一致，不能更换");
        ServiceUtil.assertion(Objects.equals(orderVO.getRoomId(), newRoom.getRoomId()), "新包间与原包间相同，无需更换");

        // 新包间在订单时间内是否有预定单  在指定时间段内是否有订单
        Date reserveStartTime = orderVO.getReserveStartTime();
        Date reserveEndTime = orderVO.getReserveEndTime();// 是否被预定  已
        int isReserved = orderValidator.isReserved(newRoom.getRoomId(), reserveStartTime, reserveEndTime);
        String reserveStartTimeString =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(reserveStartTime);
        String reserveEndTimeString =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(reserveEndTime);
        ServiceUtil.assertion(isReserved > 1, "新包间在【"+reserveStartTimeString+"】~【"+reserveEndTimeString+"】时间段内有预定单，不能更换");

    }

    @Override
    public void checkDividendProportions(List<User> dividendUsers) {
        // 使用Stream处理累加所有用户的分账比例，并且检查是否大于1
        BigDecimal totalProportion = dividendUsers.stream()
                // 映射成 BigDecimal 的分账比例
                .map(User::getDividendProportion)
                // 累加所有比例
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        // 校验
        ServiceUtil.assertion(totalProportion.compareTo(BigDecimal.ONE) > 0,"分账总比例不能大于100%");
    }

    /**
     * 进行中的订单校验
     */
    @Override
    public boolean getInProgressOrder(Long roomId) {
        int inProgressOrder = orderMapper.getInProgressOrder(roomId);
        return inProgressOrder > 0;
    }


    /**
     * 进行中的订单校验
     */
    @Override
    public boolean getInProgressOrderByIds(List<Long> roomIds) {
        if (roomIds.isEmpty()) {
            return false;
        }
        int inProgressOrder = orderMapper.getInProgressOrderByIds(roomIds);
        return inProgressOrder > 0;
    }

    /**
     * 时间段内是否有预定单
     */
    @Override
    public int isReserved(Long roomId, Date startTime, Date endTime) {
        return orderMapper.isReserved(roomId, startTime, endTime);
    }


}
