package com.tourism.webadmin.back.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaIgnore;
import com.tourism.common.core.annotation.MyRequestBody;
import com.tourism.common.core.constant.ErrorCodeEnum;
import com.tourism.common.core.object.MyOrderParam;
import com.tourism.common.core.object.ResponseResult;
import com.tourism.common.core.object.TokenData;
import com.tourism.common.core.util.MyDateUtil;
import com.tourism.common.core.util.MyModelUtil;
import com.tourism.common.dict.model.GlobalDictItem;
import com.tourism.common.dict.service.GlobalDictService;
import com.tourism.common.dict.util.GlobalDictOperationHelper;
import com.tourism.webadmin.app.website.dto.DatePriceSaveDto;
import com.tourism.webadmin.app.website.vo.DateRangePriceVo;
import com.tourism.webadmin.app.website.vo.DateRangesPriceVo;
import com.tourism.webadmin.back.dto.TourBookInfoDto;
import com.tourism.webadmin.back.dto.TourTourismProjectTravelNotesDto;
import com.tourism.webadmin.back.dto.TourismProjectDto;
import com.tourism.webadmin.back.model.*;
import com.tourism.webadmin.back.model.constant.TourCarType;
import com.tourism.webadmin.back.service.*;
import com.tourism.webadmin.back.vo.TourBookInfoVo;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * extra 后台管理系统的除生成代码外额外的controller。
 *
 * @author 吃饭睡觉
 * @date 2024-10-31
 */
@Tag(name = "extra接口")
@Slf4j
@RestController
@RequestMapping("/admin/app/extra")
public class ExtraController {

    @Autowired
    private TourismDatePriceService tourismDatePriceService;
    @Autowired
    private TourismProjectService tourismProjectService;
    @Autowired
    private TourTourismProjectTravelNotesService tourTourismProjectTravelNotesService;
    @Autowired
    private TourBookInfoService tourBookInfoService;
    @Autowired
    private GlobalDictService globalDictService;
    @Autowired
    private GlobalDictOperationHelper globalDictOperationHelper;
    @Autowired
    private TourCarDriverService tourCarDriverService;
    @Autowired
    private TourCarCategoryService tourCarCategoryService;
    /**
     * 查看指定旅游项目的日历价格。
     *
     * @param projectId 项目id。
     * @return 应答结果对象，包含对象详情。
     */
    @SaCheckPermission("tourismProject.view")
    @GetMapping("/viewDatePrice")
    public ResponseResult<List<DateRangesPriceVo>> view(@RequestParam String projectId) {

        TourismDatePrice tourismDatePrice = new TourismDatePrice();
        tourismDatePrice.setProjectId(projectId);
        tourismDatePrice.setNowDate(new Date());

        MyOrderParam myOrderParam = new MyOrderParam();
        MyOrderParam.OrderInfo orderInfo = new MyOrderParam.OrderInfo();
        orderInfo.setFieldName("departureDate");
        orderInfo.setAsc(true);
        myOrderParam.add(orderInfo);
        String orderBy = MyOrderParam.buildOrderBy(myOrderParam, TourismDatePrice.class);
        List<TourismDatePrice> tourismDatePriceList =
                tourismDatePriceService.getTourismDatePriceList(tourismDatePrice, orderBy);

        List<DateRangePriceVo> result = new ArrayList<>();
        Date startDate = null;
        Date endDate = null;
        BigDecimal currentAdultPrice = null;
        BigDecimal currentChildrenPrice = null;
        Date lastDate = null;
        for (int i = 0; i < tourismDatePriceList.size(); i++) {
            TourismDatePrice current = tourismDatePriceList.get(i);
            Date currentDate = current.getDepartureDate();
            BigDecimal currentPrice = current.getAdultPrice();
            BigDecimal currentChildPrice = current.getChildrenPrice();

            if (i == 0 || (currentDate.equals(new Date(lastDate.getTime() + 24 * 60 * 60 * 1000)) && currentPrice.equals(currentAdultPrice) && currentChildPrice.equals(currentChildrenPrice))) {
                if (startDate == null) {
                    startDate = currentDate;
                }
                endDate = currentDate;
                currentAdultPrice = currentPrice;
                currentChildrenPrice = currentChildPrice;
                lastDate = currentDate;
            } else {
                if (startDate != null) {
                    result.add(new DateRangePriceVo(startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), currentAdultPrice, currentChildrenPrice));
                }
                startDate = currentDate;
                endDate = currentDate;
                currentAdultPrice = currentPrice;
                currentChildrenPrice = currentChildPrice;
                lastDate = currentDate;
            }
        }

        // 添加最后一个范围
        if (startDate != null) {
            result.add(new DateRangePriceVo(startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(), currentAdultPrice, currentChildrenPrice));
        }

        List<DateRangesPriceVo> dateRangesPriceVoList = new ArrayList<>();

        result.stream().forEach(u->{
            DateRangesPriceVo dateRangesPriceVo = new DateRangesPriceVo();
            dateRangesPriceVo.setAdultPrice(u.getAdultPrice());
            dateRangesPriceVo.setChildrenPrice(u.getChildrenPrice());
            List<LocalDate> list = new ArrayList<>();
            list.add(u.getStartDate());list.add(u.getEndDate());
            dateRangesPriceVo.setDateRange(list);
            dateRangesPriceVoList.add(dateRangesPriceVo);
        });
        return ResponseResult.success(dateRangesPriceVoList);

    }
    /**
     * 保存指定旅游项目的日历价格。
     *
     * @param datePriceSaveDto 日历价格数组。
     * @return 应答结果对象，包含对象详情。
     */
    @Transactional
    @SaCheckPermission("tourismProject.view")
    @PostMapping("/saveDatePrice")
    public ResponseResult<Void> saveDatePrice(@RequestBody DatePriceSaveDto datePriceSaveDto) {
        //dateRangesPriceVoList为空的话，则删除全部的日历价格
        if(CollectionUtils.isEmpty(datePriceSaveDto.getDateRangesPriceVoList())){
            TourismProject tourismProject = tourismProjectService.getById(datePriceSaveDto.getProjectId());
            if(tourismProject == null){
                return ResponseResult.error(ErrorCodeEnum.DATA_SAVE_FAILED,"旅游项目不存在");
                }else {
                TourismDatePrice filter = new TourismDatePrice();
                filter.setProjectId(datePriceSaveDto.getProjectId());
                filter.setNowDate(MyDateUtil.truncateToDay(new Date()));
                List<TourismDatePrice> tourismDatePriceList = tourismDatePriceService.getTourismDatePriceList(filter, "");
                tourismDatePriceList.stream().map(TourismDatePrice::getId).forEach(item->{
                    tourismDatePriceService.removeById(item);
                });
            }
        }
        //取旅游项目的价格，来对列表数据进行对比，如果列表数据低于旅游项目的价格，则进行提示
        TourismProject tourismProject = tourismProjectService.getById(datePriceSaveDto.getProjectId());
        if(tourismProject == null){
            return ResponseResult.error(ErrorCodeEnum.DATA_SAVE_FAILED,"旅游项目不存在");
        }else {
            ArrayList<BigDecimal> adultPriceList =
                    datePriceSaveDto.getDateRangesPriceVoList().stream().map(DateRangesPriceVo::getAdultPrice).collect(Collectors.toCollection(ArrayList::new));
            ArrayList<BigDecimal> childrenPriceList =
                    datePriceSaveDto.getDateRangesPriceVoList().stream().map(DateRangesPriceVo::getChildrenPrice).collect(Collectors.toCollection(ArrayList::new));

            for(BigDecimal adultPrice : adultPriceList){
                if(tourismProject.getPrice().compareTo(adultPrice) > 0){
                return ResponseResult.error(ErrorCodeEnum.PRICE_ERROR,"成人价格不能低于旅游项目的价格");
                }
            }
            for(BigDecimal childrenPrice : childrenPriceList){
                if(tourismProject.getPrice().compareTo(childrenPrice) > 0){
                    return ResponseResult.error(ErrorCodeEnum.PRICE_ERROR,"儿童价格不能低于旅游项目的价格");
                }
            }
        }

        //进行时间范围的判断，判断时间段是否交错;交错的话，则返回时间交错的信息
        List<DateRangePriceVo> result = new ArrayList<>();
        for (DateRangesPriceVo dateRangesPriceVo : datePriceSaveDto.getDateRangesPriceVoList()) {
            DateRangePriceVo dateRangePriceVo = new DateRangePriceVo(
                    dateRangesPriceVo.getDateRange().get(0),dateRangesPriceVo.getDateRange().get(1),
                    dateRangesPriceVo.getAdultPrice(),dateRangesPriceVo.getChildrenPrice());
            result.add(dateRangePriceVo);
        }
        //转换出来时间后，判断时间是否交错
        for(int i=0;i<result.size();i++) {
            if (result.get(i).getStartDate().isEqual(result.get(i).getEndDate()) || result.get(i).getStartDate().isBefore(result.get(i).getEndDate())){
                for (int j = 0; j < result.size(); j++) {
                    if (i == j) {
                        continue;
                    }
                    //如果两条数据的开始日期或者结束日期一致的话，则进行报错返回
                    if (result.get(i).getStartDate().isEqual(result.get(j).getStartDate()) || (result.get(i).getStartDate().isEqual(result.get(j).getEndDate()))) {
//                        return ResponseResult.error(ErrorCodeEnum.DATE_OVERLAP, "开始日期为:" + result.get(i).getStartDate() + "和" + result.get(j).getStartDate() + "的时间段有重叠");
                        return ResponseResult.error(ErrorCodeEnum.DATE_OVERLAP, "第"+ (i+1) +"条数据和第" + (j+1) + "条数据的时间段有重叠");
                    }
                    if (result.get(i).getStartDate().isAfter(result.get(j).getStartDate()) && result.get(i).getStartDate().isBefore(result.get(j).getEndDate())) {
//                        return ResponseResult.error(ErrorCodeEnum.DATE_OVERLAP, "开始日期为:" + result.get(i).getStartDate() + "和" + result.get(j).getStartDate() + "的时间段有重叠");
                        return ResponseResult.error(ErrorCodeEnum.DATE_OVERLAP, "第"+ (i+1) +"条数据和第" + (j+1) + "条数据的时间段有重叠");
                    }
                    if (result.get(i).getEndDate().isAfter(result.get(j).getStartDate()) && result.get(i).getEndDate().isBefore(result.get(j).getEndDate())) {
//                        return ResponseResult.error(ErrorCodeEnum.DATE_OVERLAP, "开始日期为:" + result.get(i).getStartDate() + "和" + result.get(j).getStartDate() + "的时间段有重叠");
                        return ResponseResult.error(ErrorCodeEnum.DATE_OVERLAP, "第"+ (i+1) +"条数据和第" + (j+1) + "条数据的时间段有重叠");
                    }
                }
        }else {
                return ResponseResult.error(ErrorCodeEnum.DATE_OVERLAP, "开始日期为:" + result.get(i).getStartDate() + ",结束日期为:" + result.get(i).getEndDate() + "的时间段有误,请重新输入");
            }
        }
        //时间没有问题的话，则进行项目日历的查询，先进行删除
        TourismDatePrice filter = new TourismDatePrice();
        filter.setProjectId(datePriceSaveDto.getProjectId());
        filter.setNowDate(MyDateUtil.truncateToDay(new Date()));
        List<TourismDatePrice> tourismDatePriceList = tourismDatePriceService.getTourismDatePriceList(filter, "");
        if(!CollectionUtils.isEmpty(tourismDatePriceList)){
            tourismDatePriceService.removeByIds(tourismDatePriceList.stream().map(TourismDatePrice::getId).collect(Collectors.toList()));
        }
        //根据result构建新增的数据，再进行新增
        result.stream().forEach(item-> {
            if (item.getStartDate().equals(item.getEndDate())) {
                TourismDatePrice tourismDatePrice = new TourismDatePrice();
                tourismDatePrice.setProjectId(datePriceSaveDto.getProjectId());
                tourismDatePrice.setDepartureDate(Date.from(item.getStartDate().atStartOfDay(ZoneId.systemDefault()).toInstant()));
                tourismDatePrice.setAdultPrice(item.getAdultPrice());
                tourismDatePrice.setChildrenPrice(item.getChildrenPrice());
                tourismDatePriceService.saveNew(tourismDatePrice);
            } else {
                //对item的开始日期进行新增，直到新增到item的endDate，把中间的日期进行汇总，形成一个新的list
                List<TourismDatePrice> tourismDatePriceList1 = new ArrayList<>();
                for (LocalDate date = item.getStartDate(); date.isBefore(item.getEndDate().plusDays(1)); date = date.plusDays(1)) {
                    TourismDatePrice tourismDatePrice = new TourismDatePrice();
                    tourismDatePrice.setProjectId(datePriceSaveDto.getProjectId());
                    tourismDatePrice.setDepartureDate(Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant()));
                    tourismDatePrice.setAdultPrice(item.getAdultPrice());
                    tourismDatePrice.setChildrenPrice(item.getChildrenPrice());
                    tourismDatePriceList1.add(tourismDatePrice);
                }
                //批量新增
                tourismDatePriceService.saveNewBatch(tourismDatePriceList1);
            }
        });
        return ResponseResult.success();
    }
    /**
     * 更新项目的状态（1.启用；0.禁用。)
     *
     * @param tourismProjectDto 旅游项目管理Dto对象。
     * @return void。
     */
    @Transactional
    @SaCheckPermission("tourismProject.update")
    @PostMapping("/updateProjectState")
    public ResponseResult<Void> updateProjectState(@MyRequestBody TourismProjectDto tourismProjectDto) {
        TourismProject tourismProject = tourismProjectService.getById(tourismProjectDto.getId());
        if (tourismProject == null) {
            return ResponseResult.error(ErrorCodeEnum.PROJECT_NOT_EXIST);
        }
        if(tourismProjectDto.getEnable() == 1) {
            //查看该项目是否设置日历;设置日历，则允许修改项目状态;若未设置日历,则不允许修改项目状态
            TourismDatePrice tourismDatePrice = new TourismDatePrice();
            tourismDatePrice.setProjectId(String.valueOf(tourismProject.getId()));
            tourismDatePrice.setNowDate(new Date());
            List<TourismDatePrice> listByFilter = tourismDatePriceService.getTourismDatePriceList(tourismDatePrice,"");
            if (listByFilter.isEmpty()) {
                return ResponseResult.error(ErrorCodeEnum.DATE_PRICE_NOTEXIST);
            }
        }
        TourismProject originalTourismProject = MyModelUtil.copyTo(tourismProject, TourismProject.class);
        tourismProject.setEnable(tourismProjectDto.getEnable());
        tourismProjectService.update(tourismProject,originalTourismProject);
        return ResponseResult.success();
    }

    /**
     * 更新游记是否原创的字段（1.原创；0.非原创。)
     *
     * @param tourTourismProjectTravelNotesDto 旅游项目游记管理Dto对象。
     * @return void。
     */
    @Transactional
    @SaCheckPermission("tourTourismProjectTravelNotes.update")
    @PostMapping("/updateIsOriginalChange")
    public ResponseResult<Void> updateIsOriginalChange(@MyRequestBody TourTourismProjectTravelNotesDto tourTourismProjectTravelNotesDto) {

        TourTourismProjectTravelNotes tourTourismProjectTravelNote =
                tourTourismProjectTravelNotesService.getById(tourTourismProjectTravelNotesDto.getId());
        if(tourTourismProjectTravelNote == null){
            return ResponseResult.error(ErrorCodeEnum.PROJECT_NOT_EXIST);
        }
        TourTourismProjectTravelNotes tourTourismProjectTravelNotes =
                MyModelUtil.copyTo(tourTourismProjectTravelNote, TourTourismProjectTravelNotes.class);
        tourTourismProjectTravelNotes.setIsOriginal(tourTourismProjectTravelNotesDto.getIsOriginal());
        tourTourismProjectTravelNotesService.update(tourTourismProjectTravelNotes,tourTourismProjectTravelNote);
        return ResponseResult.success();
    }


    /**
     * 查看指定门户预定管理对象详情。
     *
     * @param tourBookInfoDtoFilter 过滤对象。
     * @return 应答结果对象，包含对象详情。
     */
    @SaCheckPermission("tourBookInfo.view")
    @PostMapping("/isHandleChange")
    public ResponseResult<Void> isHandleChange(@MyRequestBody TourBookInfoDto tourBookInfoDtoFilter) {
        TourBookInfo tourBookInfo = tourBookInfoService.getById(tourBookInfoDtoFilter.getId());
        if(tourBookInfo == null){
            return ResponseResult.error(ErrorCodeEnum.PROJECT_NOT_EXIST);
        }
        TourBookInfo tourBookInfo1 =
                MyModelUtil.copyTo(tourBookInfo, TourBookInfo.class);
        tourBookInfo1.setIsHandle(tourBookInfoDtoFilter.getIsHandle());
        tourBookInfoService.update(tourBookInfo1,tourBookInfo);
        return ResponseResult.success();
    }

    /**
     * 获取指定字典编码的全局字典项目。字典的键值为[itemId, itemName]。
     * NOTE: 白名单接口。
     *
     * @param dictCode   字典编码。
     * @param itemIdType 字典项目的ItemId值转换到的目标类型。可能值为Integer或Long。
     * @return 应答结果对象。
     */
    @SaIgnore
    @GetMapping("/listDict")
    public ResponseResult<List<Map<String, Object>>> listDict(
            @RequestParam String dictCode, @RequestParam(required = false) String itemIdType) {
        List<GlobalDictItem> resultList =
                globalDictService.getGlobalDictItemListFromCache(dictCode, null);
        resultList = resultList.stream()
                .filter(item -> item.getStatus() == 0)
                .sorted(Comparator.comparing(GlobalDictItem::getShowOrder))
                .collect(Collectors.toList());
        return ResponseResult.success(globalDictOperationHelper.toDictDataList(resultList, itemIdType));
    }


    /**
     * 在新建司机时，进行判断是否为第三方，第三方的话，验证是否已经存在信息。存在信息--->返回error。
     *
     *
     * @return 应答结果对象，包含对象详情。
     */
    @SaCheckPermission("tourCarDriver.add")
    @GetMapping("/existDriver")
    public ResponseResult<Void> existDriver() {
        Long userId = TokenData.takeFromRequest().getUserId();
        TourCarDriver tourCarDriverFilter = new TourCarDriver();
        tourCarDriverFilter.setCreateUserId(userId);
        tourCarDriverFilter.setType(TourCarType.THIRD_PARTY_INDIVIDUAL);
        boolean b = tourCarDriverService.existByFilter(tourCarDriverFilter);
        if(b){
            return ResponseResult.error(ErrorCodeEnum.ONLY_ONE);
        }
        return ResponseResult.success();
    }


    /**
     * 在新建车型信息时，进行判断是否为第三方，第三方的话，验证是否已经存在信息。存在信息--->返回error。
     *
     *
     * @return 应答结果对象，包含对象详情。
     */
    @SaCheckPermission("tourCarCategory.add")
    @GetMapping("/existCarCategory")
    public ResponseResult<Void> existCarCategory() {
        Long userId = TokenData.takeFromRequest().getUserId();
        TourCarCategory tourCarCategoryFilter = new TourCarCategory();
        tourCarCategoryFilter.setCreateUserId(userId);
        tourCarCategoryFilter.setType(TourCarType.THIRD_PARTY_INDIVIDUAL);
        boolean b = tourCarCategoryService.existByFilter(tourCarCategoryFilter);
        if(b){
            return ResponseResult.error(ErrorCodeEnum.ONLY_ONE);
        }
        return ResponseResult.success();
    }


    /**
     * 在进行管理员不可进行的操作时，判断是否为管理员;
     *
     *
     * @return 应答结果对象，包含对象详情。
     */
//    @SaCheckPermission("tourCarCategory.add")
    @GetMapping("/isAdmin")
    public ResponseResult<Void> isAdmin() {
        //查看账号是否为管理员权限,设定管理员为全部可见,但不允许管理员直接修改;
        Boolean isAdmin = TokenData.takeFromRequest().getIsAdmin();
        if(isAdmin){
            return ResponseResult.error(ErrorCodeEnum.ADMIN_NO_OPTION);
        }
        return ResponseResult.success();
    }


    /**
     * 新增第三方车型之前，校验该用户是否已经创建第三方司机信息;
     *
     *
     * @return 应答结果对象，包含对象详情。
     */
    @GetMapping("/verifyDriverInfo")
    public ResponseResult<Void> verifyDriverInfo() {

        Long userId = TokenData.takeFromRequest().getUserId();
        TourCarDriver tourCarDriver = new TourCarDriver();
        tourCarDriver.setCreateUserId(userId);
        boolean b = tourCarDriverService.existByFilter(tourCarDriver);
        //如果没有该用户创建的司机信息，则进行提醒-->先创建司机信息
        if(!b){
            return ResponseResult.error(ErrorCodeEnum.CREATE_DRIVER_INFO);
        }
        return ResponseResult.success();
    }


    /**
     * 第三方司机删除司机数据前，增加对第三方车辆的校验(判断是否已经删除第三方车辆了);
     *
     *
     * @return 应答结果对象，包含对象详情。
     */
    @GetMapping("/verifyDelCarInfo")
    public ResponseResult<Void> verifyDelCarInfo() {
        Long userId = TokenData.takeFromRequest().getUserId();
        TourCarCategory tourCarCategory = new TourCarCategory();
        tourCarCategory.setCreateUserId(userId);
        boolean b = tourCarCategoryService.existByFilter(tourCarCategory);
        if(b){
            return ResponseResult.error(ErrorCodeEnum.VERIFY_THIRD_CARINFO);
        }
        return ResponseResult.success();
    }


}
