package com.xxfc.platform.vehicle.rest;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.github.wxiaoqi.security.admin.feign.UserFeign;
import com.github.wxiaoqi.security.admin.feign.rest.UserRestInterface;
import com.github.wxiaoqi.security.auth.client.annotation.IgnoreClientToken;
import com.github.wxiaoqi.security.auth.client.annotation.IgnoreUserToken;
import com.github.wxiaoqi.security.common.exception.BaseException;
import com.github.wxiaoqi.security.common.msg.ObjectRestResponse;
import com.github.wxiaoqi.security.common.util.process.ResultCode;
import com.github.wxiaoqi.security.common.vo.PageDataVO;
import com.xxfc.platform.vehicle.biz.VehicleBiz;
import com.xxfc.platform.vehicle.biz.VehicleHolidayPriceInfoBiz;
import com.xxfc.platform.vehicle.biz.VehiclePlatCataBiz;
import com.xxfc.platform.vehicle.common.BaseController;
import com.xxfc.platform.vehicle.common.RestResponse;
import com.xxfc.platform.vehicle.constant.BookType;
import com.xxfc.platform.vehicle.constant.VehicleBookRecordStatus;
import com.xxfc.platform.vehicle.constant.VehicleMemberType;
import com.xxfc.platform.vehicle.entity.Vehicle;
import com.xxfc.platform.vehicle.entity.VehicleBookRecord;
import com.xxfc.platform.vehicle.pojo.*;
import com.xxfc.platform.vehicle.pojo.dto.VehicleModelCalendarPriceDTO;
import com.xxfc.platform.vehicle.pojo.vo.UsableVeicleVO;
import com.xxfc.platform.vehicle.pojo.vo.VehicleVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.HashSet;
import java.util.List;

import static com.github.wxiaoqi.security.common.constant.CommonConstants.*;
import static com.xxfc.platform.vehicle.constant.VehicleConstant.USER_APP;
import static com.xxfc.platform.vehicle.constant.VehicleConstant.USER_APP_NAME;

@RestController
@RequestMapping("/vehicleInfo")
@Slf4j
@IgnoreClientToken
@Api(value="租车相关车辆管理controller",tags={"租车相关车辆管理接口"})
public class RentVehicleController extends BaseController<VehicleBiz> implements UserRestInterface {

    @Autowired
    private VehiclePlatCataBiz vehiclePlatCataBiz;

    @Autowired
    UserFeign userFeign;

    @Autowired
    VehicleBiz vehicleBiz;

    @Autowired
    VehicleHolidayPriceInfoBiz vehicleHolidayPriceInfoBiz;

    public UserFeign getUserFeign() {
        return userFeign;
    }

    /**
     * 租车拒绝预定车辆申请
     *
     * @param bookRecordId
     * @return
     */
    @RequestMapping(value = "/rent/book/reject/{bookRecordId}", method = RequestMethod.PUT)
    @ApiOperation(value = "租车拒绝预定车辆")
    @IgnoreUserToken
    public RestResponse<Integer> rentRejectVehicleBooking(@PathVariable Long bookRecordId) throws Exception {
        //默认USER_APP 预约
        Integer operatorId = USER_APP;
        String userName = USER_APP_NAME;
        return baseBiz.reviewVehicleBooking(operatorId, bookRecordId, VehicleBookRecordStatus.REJECTED.getCode(), userName, "租车订单取消", Boolean.TRUE);
    }

    /**
     * 取消车辆预订
     *
     * @param bookRecordId
     * @return
     */
    @RequestMapping(value = "/rent/unbook/{bookRecordId}", method = RequestMethod.DELETE)
    @ApiOperation(value = "取消预定车辆")
    @IgnoreUserToken
    public RestResponse<Integer> rentUnbookVehicle(@PathVariable Long bookRecordId) throws Exception {
        //默认USER_APP 预约
        Integer operatorId = USER_APP;
        String userName = USER_APP_NAME;
        return baseBiz.unbookVehicle4Employee(operatorId, bookRecordId, userName,null, Boolean.TRUE);
    }

    /**
     * 批准预定车辆预定
     *
     * @param bookRecordId
     * @return
     */
    @RequestMapping(value = "/rent/book/prove/{bookRecordId}", method = RequestMethod.PUT)
    @ApiOperation(value = "预定车辆审核通过")
    @IgnoreUserToken
    public RestResponse<Integer> rentProveVehicleBooking(@PathVariable Long bookRecordId) throws Exception {
        //默认USER_APP 预约
        Integer operatorId = USER_APP;
        String userName = USER_APP_NAME;
        return baseBiz.reviewVehicleBooking(operatorId, bookRecordId, VehicleBookRecordStatus.APPROVE.getCode(), userName, "", Boolean.TRUE);
    }

    /**
     * 可用车辆查询
     *
     * @param dto
     * @return
     */
    @ApiOperation("可用车辆查询")
    @RequestMapping(value = "/rent/usable-vehicle", method = RequestMethod.GET)
    @IgnoreUserToken
    public ObjectRestResponse<PageDataVO<UsableVehicleModelVO>> rentUsableVehicle(UsableVeicleDTO dto) throws Exception {
        //根据时间 获得 可用车辆
        //结合车型
        if (StringUtils.isNotBlank(dto.getCatasStr())) {
            dto.setCatas(vehiclePlatCataBiz.groupCatasByParent(dto.getCatasStr()));
        }
        //设置显示是否有车（通过把时间与位比较从where移动到select）
        //dto.setYearNo4Where(Boolean.TRUE);
        //dto.setWithoutRecordWhere(SYS_TRUE);
        //匹配相交叉的预约记录
        dto.setRecordIntersection(Boolean.TRUE);
        PageDataVO<UsableVehicleModelVO> uvmvpdvs = vehicleBiz.searchUsableModel(dto);
        if(CollUtil.isNotEmpty(uvmvpdvs.getData())){
            uvmvpdvs.getData().forEach(data -> {
                data.setHasVehicle(SYS_FALSE);
//                if(StrUtil.isNotBlank(data.getVehicleIds())) {
//                    String[] strs = StrUtil.split(data.getVehicleIds(), ",");
//                    List<Vehicle> vehicleList = vehicleBiz.selectByWeekend(w -> {
//                        w.andIn(Vehicle::getId, CollUtil.toList(strs));
//                        return w;
//                    });
//                    vehicleList.forEach(vehicle -> {
//                        baseBiz
//                    });
//                }
                RentVehicleBookDTO rbd = new RentVehicleBookDTO();
                rbd.setModelId(data.getVehicleModel().getId());
                rbd.setLimit(20);
                rbd.setPage(1);
                rbd.setParkBranchCompanyId(dto.getStartCompanyId());
                rbd.setStartCompanyId(dto.getStartCompanyId());
                rbd.setEndCompanyId(dto.getEndCompanyId());
                rbd.setBookStartDate(dto.getStartDate());
                rbd.setBookEndDate(dto.getEndDate());
                rbd.setRecordIntersection(Boolean.TRUE);
                rbd.setBookStartDateTime(dto.getStartDateTime());
                rbd.setBookEndDateTime(dto.getEndDateTime());
                rbd.setYearNo4Where(Boolean.TRUE);
                //查询可车辆信息
                PageDataVO<UsableVeicleVO> pageDataVO = vehicleBiz.searchUsableVehicle(rbd);
                if(CollUtil.isNotEmpty(pageDataVO.getData())) {

                    for (UsableVeicleVO usableVeicleVO : pageDataVO.getData()) {

                        //判断是否预定时间内可租
                        usableVeicleVO.setAllowRent(SYS_TRUE);
                        //如果"必须在这时间后预定" 存在 并且 比预定开始时间 要晚，那么不允许预定
                        if(null != usableVeicleVO.getToLiftMustAfterDate() && DateUtil.date(dto.getStartDateTamp()).isBeforeOrEquals(usableVeicleVO.getToLiftMustAfterDate())) {
                            usableVeicleVO.setAllowRent(SYS_FALSE);
                        }

                        //如果"必须在这时间前预定" 存在 并且 比预定结束时间 要早，那么不允许预定
                        if(null != usableVeicleVO.getToReturnMustBeforeDate() && DateUtil.date(dto.getEndDateTamp()).isAfterOrEquals(usableVeicleVO.getToReturnMustBeforeDate())) {
                            usableVeicleVO.setAllowRent(SYS_FALSE);
                        }else {
                            data.setHasVehicle(SYS_TRUE);
                        }

                        String priceStartDateStr = StrUtil.isNotBlank(dto.getPriceStartDate())? dto.getPriceStartDate(): dto.getStartDate();
                        String priceEndDateStr = StrUtil.isNotBlank(dto.getPriceEndDate())? dto.getPriceEndDate(): dto.getEndDate();

                        usableVeicleVO.setPriceDTOS(vehicleHolidayPriceInfoBiz.getSynthesizePrice(usableVeicleVO.getId(), priceStartDateStr, priceEndDateStr, null, usableVeicleVO.getSubordinateBranch()));
                    }
                    data.setUsableVeicleVOList(pageDataVO.getData());
                }
            });
        }
        return ObjectRestResponse.succ(uvmvpdvs);
    }

    /**
     * 后台查询可用车辆(车型)
     *
     * @param dto
     * @return
     */
    @ApiOperation("后台可用车辆查询")
    @RequestMapping(value = "/rent/back-stage/usable-vehicle", method = RequestMethod.GET)
    @IgnoreUserToken
    public ObjectRestResponse<PageDataVO<UsableVehicleModelVO>> rentBgUsableVehicle(UsableVeicleDTO dto) throws Exception {
        //根据时间 获得 可用车辆
        //结合车型
        if (StringUtils.isNotBlank(dto.getCatasStr())) {
            dto.setCatas(vehiclePlatCataBiz.groupCatasByParent(dto.getCatasStr()));
        }
        //设置显示是否有车（通过把时间与位比较从where移动到select）
        dto.setYearNo4Where(Boolean.TRUE);
        //dto.setUseType(null);
        return ObjectRestResponse.succ(vehicleBiz.searchUsableModelBackStage(dto));
    }

    /**
     * 热门车型
     *
     * @param dto
     * @return
     */
    @ApiOperation("热门车型")
    @RequestMapping(value = "/rent/hot-vehicle", method = RequestMethod.GET)
    @IgnoreUserToken
    public ObjectRestResponse<PageDataVO<UsableVehicleModelVO>> hotVehicle(HotVeicleDTO dto) throws Exception {
        return ObjectRestResponse.succ(vehicleBiz.hotModel(dto));
    }

    /**
     * 租车触发的申请预定车辆
     *
     * @param dto
     * @return
     */
    @ApiOperation("租车触发的申请预定车辆")
    @RequestMapping(value = "/rent/book/vehicle", method = RequestMethod.POST)
    @IgnoreClientToken
    @IgnoreUserToken
    public ObjectRestResponse<VehicleBookRecord> rentApplyVehicle(@RequestBody RentVehicleBookDTO dto) throws Exception {
        //默认USER_APP 预约
        Integer operatorId = USER_APP;
        String userName = dto.getUserName();
        String bookVehicleId;
        if(StrUtil.isNotBlank(dto.getNumberPlate())) {
            Vehicle vehicle = vehicleBiz.selectOne(new Vehicle(){{
                setNumberPlate(dto.getNumberPlate());
                setIsDel(SYS_FALSE);
            }});
            bookVehicleId = vehicle.getId();
        }else if(null != dto.getVehicleId()){
            bookVehicleId = dto.getVehicleId();
        }else {
            dto.setLimit(1);
            dto.setPage(1);
            dto.setParkBranchCompanyId(dto.getLiftCompany());
            dto.setStartCompanyId(dto.getLiftCompany());
            dto.setEndCompanyId(dto.getEndCompanyId());
            //查询可车辆信息
            PageDataVO<UsableVeicleVO> pageDataVO = vehicleBiz.searchUsableVehicle(dto);
            if (pageDataVO.getData().size() <= 0 && (dto.getMemberUse() == null || dto.getMemberUse().equals(VehicleMemberType.NO.getCode()))) {

                throw new BaseException(ResultCode.NOTEXIST_CODE, new HashSet<String>(){{
                    add("可用车辆不存在");
                }});
            } else  if (pageDataVO.getData().size() <= 0 && (dto.getMemberUse() == null ||!dto.getMemberUse().equals(VehicleMemberType.NO.getCode()))) {
                throw new BaseException(ResultCode.NOTEXIST_CODE, new HashSet<String>(){{
                    add("仅剩托管车辆，无法使用免费天数，请关闭会员特权");
                }});
            }
            bookVehicleId = pageDataVO.getData().get(0).getId();
        }
        //判断是否为今天，如果是则设置为30秒后开始 防止预约开始时间比当前时间 要 前
        if(DateUtil.today().equals(dto.getBookStartDate())) {
            LocalDateTime ldt = LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneOffset.ofHours(8)).plusSeconds(30L);
            dto.setBookStartDate(DateTimeFormatter.ofPattern(DATE_TIME_LINE).format(ldt));
        }else {
            dto.setBookStartDate(dto.getBookStartDateTime());
        }
        dto.setBookEndDate(dto.getBookEndDateTime());
        BookVehicleVO bookVehicleVo = BeanUtil.toBean(dto, BookVehicleVO.class);
        bookVehicleVo.setBookType(BookType.USER_RENT.getCode());
        bookVehicleVo.setVehicleId(bookVehicleId);
        if(null != dto.getStatus()) {
            bookVehicleVo.setStatus(dto.getStatus());
        }else {
            bookVehicleVo.setStatus(VehicleBookRecordStatus.APPLY.getCode());
        }
        VehicleBookRecord vehicleBookRecord = baseBiz.applyVehicle(operatorId, bookVehicleVo, userName);
        return ObjectRestResponse.succ(vehicleBookRecord);
    }
}
