/*
 * Copyright [2022] [https://www.xiaonuo.vip]
 *
 * Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：
 *
 * 1.请不要删除和修改根目录下的LICENSE文件。
 * 2.请不要删除和修改Snowy源码头部的版权声明。
 * 3.本项目代码可免费商业使用，商业使用请保留源码和相关描述文件的项目出处，作者声明等。
 * 4.分发源码时候，请注明软件出处 https://www.xiaonuo.vip
 * 5.不可二次分发开源参与同类竞品，如有想法可联系团队xiaonuobase@qq.com商议合作。
 * 6.若您的项目无法满足以上几点，需要更多功能代码，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.biz.modular.bizappointmenttime.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.framework.qual.QualifierArgument;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.biz.modular.bizconfig.entity.BizConfig;
import vip.xiaonuo.biz.modular.bizconfig.service.BizConfigService;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.page.CommonPageRequest;
import vip.xiaonuo.biz.modular.bizappointmenttime.entity.BizAppointmentTime;
import vip.xiaonuo.biz.modular.bizappointmenttime.mapper.BizAppointmentTimeMapper;
import vip.xiaonuo.biz.modular.bizappointmenttime.param.BizAppointmentTimeAddParam;
import vip.xiaonuo.biz.modular.bizappointmenttime.param.BizAppointmentTimeEditParam;
import vip.xiaonuo.biz.modular.bizappointmenttime.param.BizAppointmentTimeIdParam;
import vip.xiaonuo.biz.modular.bizappointmenttime.param.BizAppointmentTimePageParam;
import vip.xiaonuo.biz.modular.bizappointmenttime.service.BizAppointmentTimeService;

import java.time.LocalTime;
import java.util.List;

/**
 * 预约时段配置Service接口实现类
 *
 * @author fanzherong
 * @date  2025/03/20 17:46
 **/
@Service
@Slf4j
public class BizAppointmentTimeServiceImpl extends ServiceImpl<BizAppointmentTimeMapper, BizAppointmentTime> implements BizAppointmentTimeService {

    @Resource
    private BizConfigService bizConfigService;

    @Override
    public Page<BizAppointmentTime> page(BizAppointmentTimePageParam bizAppointmentTimePageParam) {
        QueryWrapper<BizAppointmentTime> queryWrapper = new QueryWrapper<BizAppointmentTime>().checkSqlInjection();
        queryWrapper.lambda().orderByAsc(BizAppointmentTime::getBeginTime);
        return this.page(CommonPageRequest.defaultPage(), queryWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(BizAppointmentTimeAddParam bizAppointmentTimeAddParam) {
        checkAddParam(bizAppointmentTimeAddParam);
        BizAppointmentTime bizAppointmentTime = BeanUtil.toBean(bizAppointmentTimeAddParam, BizAppointmentTime.class);
        if(StringUtils.equals(bizAppointmentTime.getEndTime(),"00:00")){
            bizAppointmentTime.setFinishTime("24:00");
        }else{
            bizAppointmentTime.setFinishTime(bizAppointmentTime.getEndTime());
        }
        this.save(bizAppointmentTime);
    }

    public void checkAddParam(BizAppointmentTimeAddParam bizAppointmentTimeAddParam){
        //根据时间段查询
        List<BizAppointmentTime> appointmentTimeList = this.list(new QueryWrapper<BizAppointmentTime>().lambda().
                eq(BizAppointmentTime::getBeginTime, bizAppointmentTimeAddParam.getBeginTime()).
                eq(BizAppointmentTime::getEndTime, bizAppointmentTimeAddParam.getEndTime()));
        if(ObjectUtil.isNotEmpty(appointmentTimeList)){
            throw new CommonException("当前时间段已经存在，不可添加！");
        }

        //新增时选择的时间段
        Integer beginTimeAddone = Integer.parseInt(bizAppointmentTimeAddParam.getBeginTime().split(":")[0]);
        Integer beginTimeAddTwo = Integer.parseInt(bizAppointmentTimeAddParam.getBeginTime().split(":")[1]);

        Integer endTimeAddOne = Integer.parseInt(bizAppointmentTimeAddParam.getEndTime().split(":")[0]);
        Integer endTimeAddTwo = Integer.parseInt(bizAppointmentTimeAddParam.getEndTime().split(":")[1]);

        //校验添加结束时间段可能大于等于开始时间段
        if(checkAddTime(LocalTime.of(beginTimeAddone,beginTimeAddTwo),LocalTime.of(endTimeAddOne,endTimeAddTwo))){
            throw new CommonException("开始时间段不能大于等于结束时间段且不能添加跨天的时间段！");
        }
        List<BizAppointmentTime> list = this.list();
        for(BizAppointmentTime appointmentTime : list){
            //开始时间段
            Integer beginTimeOne = Integer.parseInt(appointmentTime.getBeginTime().split(":")[0]);
            Integer beginTimeTwo = Integer.parseInt(appointmentTime.getBeginTime().split(":")[1]);

            Integer endTimeOne = Integer.parseInt(appointmentTime.getEndTime().split(":")[0]);
            Integer endTimeTwo = Integer.parseInt(appointmentTime.getEndTime().split(":")[1]);


            if(hasIntersection(LocalTime.of(beginTimeAddone,beginTimeAddTwo),LocalTime.of(endTimeAddOne,endTimeAddTwo),
                    LocalTime.of(beginTimeOne,beginTimeTwo),LocalTime.of(endTimeOne,endTimeTwo))
            ){
                throw new CommonException("当前时间段和添加过的时间段有交集，不可添加！");
            }
        }
    }

    public void checkEditParam(BizAppointmentTimeEditParam bizAppointmentTimeEditParam){
        //根据时间段查询
        List<BizAppointmentTime> appointmentTimeList = this.list(new QueryWrapper<BizAppointmentTime>().lambda().
                eq(BizAppointmentTime::getBeginTime, bizAppointmentTimeEditParam.getBeginTime()).
                eq(BizAppointmentTime::getEndTime, bizAppointmentTimeEditParam.getEndTime()));
        if(ObjectUtil.isNotEmpty(appointmentTimeList)){
            throw new CommonException("当前时间段已经存在，不可添加！");
        }

        //新增时选择的时间段
        Integer beginTimeAddone = Integer.parseInt(bizAppointmentTimeEditParam.getBeginTime().split(":")[0]);
        Integer beginTimeAddTwo = Integer.parseInt(bizAppointmentTimeEditParam.getBeginTime().split(":")[1]);

        Integer endTimeAddOne = Integer.parseInt(bizAppointmentTimeEditParam.getEndTime().split(":")[0]);
        Integer endTimeAddTwo = Integer.parseInt(bizAppointmentTimeEditParam.getEndTime().split(":")[1]);

        //校验添加结束时间段可能大于等于开始时间段
        if(checkAddTime(LocalTime.of(beginTimeAddone,beginTimeAddTwo),LocalTime.of(endTimeAddOne,endTimeAddTwo))){
            throw new CommonException("开始时间段不能大于等于结束时间段且不能添加跨天的时间段！");
        }
        List<BizAppointmentTime> list = this.list();
        for(BizAppointmentTime appointmentTime : list){
            //开始时间段
            Integer beginTimeOne = Integer.parseInt(appointmentTime.getBeginTime().split(":")[0]);
            Integer beginTimeTwo = Integer.parseInt(appointmentTime.getBeginTime().split(":")[1]);

            Integer endTimeOne = Integer.parseInt(appointmentTime.getEndTime().split(":")[0]);
            Integer endTimeTwo = Integer.parseInt(appointmentTime.getEndTime().split(":")[1]);


            if(hasIntersection(LocalTime.of(beginTimeAddone,beginTimeAddTwo),LocalTime.of(endTimeAddOne,endTimeAddTwo),
                    LocalTime.of(beginTimeOne,beginTimeTwo),LocalTime.of(endTimeOne,endTimeTwo))
            ){
                throw new CommonException("当前时间段和添加过的时间段有交集，不可添加！");
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(BizAppointmentTimeEditParam bizAppointmentTimeEditParam) {
        BizAppointmentTime bizAppointmentTime = this.queryEntity(bizAppointmentTimeEditParam.getId());
        if(!StringUtils.equals(bizAppointmentTime.getBeginTime(),bizAppointmentTimeEditParam.getBeginTime()) ||
            !StringUtils.equals(bizAppointmentTime.getEndTime(),bizAppointmentTimeEditParam.getEndTime())){
            checkEditParam(bizAppointmentTimeEditParam);
        }
        BeanUtil.copyProperties(bizAppointmentTimeEditParam, bizAppointmentTime);
        if(StringUtils.equals(bizAppointmentTime.getEndTime(),"00:00")){
            bizAppointmentTime.setFinishTime("24:00");
        }else{
            bizAppointmentTime.setFinishTime(bizAppointmentTime.getEndTime());
        }
        this.updateById(bizAppointmentTime);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<BizAppointmentTimeIdParam> bizAppointmentTimeIdParamList) {
        // 执行删除
        this.removeByIds(CollStreamUtil.toList(bizAppointmentTimeIdParamList, BizAppointmentTimeIdParam::getId));
    }

    @Override
    public BizAppointmentTime detail(BizAppointmentTimeIdParam bizAppointmentTimeIdParam) {
        return this.queryEntity(bizAppointmentTimeIdParam.getId());
    }

    @Override
    public BizAppointmentTime queryEntity(String id) {
        BizAppointmentTime bizAppointmentTime = this.getById(id);
        if(ObjectUtil.isEmpty(bizAppointmentTime)) {
            throw new CommonException("预约时段配置不存在，id值为：{}", id);
        }
        return bizAppointmentTime;
    }

    @Override
    public List<BizAppointmentTime> getDownList() {
        List<BizAppointmentTime> timeList = Lists.newArrayList();
        //获取配置的时段下拉个数
        BizConfig bizConfig = bizConfigService.getOne(new QueryWrapper<BizConfig>().lambda().last("limit 1"));
        String format = DateUtil.format(DateUtil.date(), "HH:mm");
        //查询大于等于当前时间的时间段个数
        List<BizAppointmentTime> list = this.list(new QueryWrapper<BizAppointmentTime>().lambda().
                and(wrapper->wrapper.ge(BizAppointmentTime::getBeginTime, format).or().gt(BizAppointmentTime::getFinishTime,format)).
                orderByAsc(BizAppointmentTime::getBeginTime));
        //如果查询到的时段个数大于等于配置的下拉个数,直接返回，反之，从前面查询补上
        if(list.size()>= bizConfig.getPullNumber()){
            timeList.addAll(list.subList(0,bizConfig.getPullNumber()));
        }else{
            //差额
            timeList.addAll(list);
            int count = bizConfig.getPullNumber() - list.size();
            List<BizAppointmentTime> bizAppointmentTimeList = this.list(new QueryWrapper<BizAppointmentTime>().lambda().
                    ge(BizAppointmentTime::getBeginTime,  "00:00").
                    orderByAsc(BizAppointmentTime::getBeginTime).
                    last("limit "+count));
            timeList.addAll(bizAppointmentTimeList);
        }
        return timeList;
    }

    public static void main(String[] args) {
        String format = DateUtil.format(DateUtil.date(), "HH");
        System.out.printf("format:"+format);
    }


    public static boolean checkAddTime(LocalTime startA, LocalTime endA){
        if(startA.isAfter(endA)){
            if(endA == LocalTime.of(0,0)){
                return false;
            }
            return true;
        }else if(startA.isBefore(endA)){
            return false;
        }else{
            return true;
        }
    }

    public static boolean hasIntersection(LocalTime startA, LocalTime endA, LocalTime startB, LocalTime endB) {
        // 如果时间段 B 结束于次日，则需要特殊处理，A 没有跨天
        if (endB.isBefore(startB) && endA.isAfter(startA)) {
            if(startA.isAfter(endB) && startB.isBefore(endA)){
                return true;
            }else{
                return false;
            }
        } else if(endA.isBefore(startA) && endB.isAfter(startB)){
            // 时段A 跨午夜 b 没有跨天
            if(startA.isBefore(endB) && startB.isAfter(endA)){
                return true;
            }else{
                return false;
            }
        } else if(endA.isBefore(startA) && endB.isBefore(startB)){
            //时段A跨天  时段b跨天
            if(startA.isAfter(endB) && startB.isAfter(endA)){
                return true;
            }else{
                return false;
            }
        }else {
            // 时间段 B 没有跨越午夜
            // 使用常规的交集判断逻辑
            return startA.isBefore(endB) && startB.isBefore(endA);
        }
    }
}
