package org.dromara.system.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.dromara.common.core.service.OssService;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.redis.utils.CacheUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.TblDzbcPath;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.domain.vo.TblDzbcCarVo;
import org.dromara.system.domain.vo.TblDzbcMultiSitePathVo;
import org.dromara.system.domain.vo.TblDzbcPathVo;
import org.dromara.system.domain.TblDzbcDriverTrip;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.mapper.TblDzbcCarMapper;
import org.dromara.system.mapper.TblDzbcDriverTripMapper;
import org.dromara.system.mapper.TblDzbcMultiSitePathMapper;
import org.dromara.system.mapper.TblDzbcPathMapper;
import org.springframework.stereotype.Service;
import org.dromara.system.domain.bo.TblDzbcDriverTripBo;
import org.dromara.system.domain.bo.TblDzbcPathSchedulingBo;
import org.dromara.system.domain.vo.TblDzbcPathSchedulingVo;
import org.dromara.system.domain.TblDzbcPathScheduling;
import org.dromara.system.mapper.TblDzbcPathSchedulingMapper;
import org.dromara.system.service.ITblDzbcDriverTripService;
import org.dromara.system.service.ITblDzbcPathSchedulingService;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 定制班车-路线排班Service业务层处理
 *
 * @author Lion Li
 * @date 2025-02-12
 */
@RequiredArgsConstructor
@Service
public class TblDzbcPathSchedulingServiceImpl implements ITblDzbcPathSchedulingService {

    private final TblDzbcPathSchedulingMapper baseMapper;

    private final TblDzbcCarMapper carMapper;
    private final TblDzbcPathMapper pathMapper;
    private final TblDzbcMultiSitePathMapper multiSitePathMapper;
    private final ITblDzbcDriverTripService driverTripService;
    private final TblDzbcDriverTripMapper driverTripMapper;

    private final SysUserMapper userMapper;
    private final OssService ossService;

    /**
     * 查询定制班车-路线排班
     */
    @Override
    public TblDzbcPathSchedulingVo queryById(Long id){
        SysCache();
        TblDzbcPathSchedulingVo vo = baseMapper.selectVoById(id);
        if (vo != null && vo.getExt2() != null) {
            try {
                JSONObject ext2 = JSONUtil.parseObj(vo.getExt2());
                if (ext2.containsKey("type")) {
                    vo.setType(ext2.getInt("type"));
                }
            } catch (Exception e) {}
        }
        return vo;
    }

    /**
     * 查询定制班车-路线排班列表
     */
    @Override
    public TableDataInfo<TblDzbcPathSchedulingVo> queryPageList(TblDzbcPathSchedulingBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<TblDzbcPathScheduling> lqw = buildQueryWrapper(bo);
        Page<TblDzbcPathSchedulingVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        result.getRecords().forEach(vo -> {
            if (vo.getExt2() != null) {
                try {
                    JSONObject ext2 = JSONUtil.parseObj(vo.getExt2());
                    if (ext2.containsKey("type")) {
                        vo.setType(ext2.getInt("type"));
                    }
                } catch (Exception e) {}
            }
            // 固定路线(type=2)时，通过 driverTrip 判断发车状态
            if (vo.getType() != null && vo.getType() == 2) {
                try {
                    // 通过 schedulingId 查询对应的 driverTrip
                    TblDzbcDriverTrip trip = driverTripMapper.selectOne(
                        new LambdaQueryWrapper<TblDzbcDriverTrip>()
                            .apply("ext2->'$.schedulingId' = {0}", vo.getId())
                            .last("LIMIT 1")
                    );
                    if (trip != null) {
                        // status: 0-待发车 1-运行中 2-已完成 3-已取消
                        if (trip.getStatus() != null && trip.getStatus() >= 1) {
                            vo.setCarStatus("已发车");
                        }
                    }
                } catch (Exception e) {}
            }
        });
        return TableDataInfo.build(result);
    }

    /**
     * 查询定制班车-路线排班列表
     */
    @Override
    public List<TblDzbcPathSchedulingVo> queryList(TblDzbcPathSchedulingBo bo) {
        LambdaQueryWrapper<TblDzbcPathScheduling> lqw = buildQueryWrapper(bo);
        List<TblDzbcPathSchedulingVo> list = baseMapper.selectVoList(lqw);
        list.forEach(vo -> {
            if (vo.getExt2() != null) {
                try {
                    JSONObject ext2 = JSONUtil.parseObj(vo.getExt2());
                    if (ext2.containsKey("type")) {
                        vo.setType(ext2.getInt("type"));
                    }
                } catch (Exception e) {}
            }
        });
        return list;
    }

    private LambdaQueryWrapper<TblDzbcPathScheduling> buildQueryWrapper(TblDzbcPathSchedulingBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<TblDzbcPathScheduling> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getPathId() != null, TblDzbcPathScheduling::getPathId, bo.getPathId());
        lqw.eq(bo.getCarId() != null, TblDzbcPathScheduling::getCarId, bo.getCarId());
        lqw.eq(bo.getMdate() != null, TblDzbcPathScheduling::getMdate, bo.getMdate());
        lqw.eq(bo.getIsauto() != null, TblDzbcPathScheduling::getIsauto, bo.getIsauto());
        lqw.eq(StringUtils.isNotBlank(bo.getMtime()), TblDzbcPathScheduling::getMtime, bo.getMtime());
        lqw.eq(StringUtils.isNotBlank(bo.getStartSites()), TblDzbcPathScheduling::getStartSites, bo.getStartSites());
        lqw.eq(StringUtils.isNotBlank(bo.getEndSites()), TblDzbcPathScheduling::getEndSites, bo.getEndSites());
        lqw.eq(StringUtils.isNotBlank(bo.getExt1()), TblDzbcPathScheduling::getExt1, bo.getExt1());
        lqw.eq(StringUtils.isNotBlank(bo.getExt2()), TblDzbcPathScheduling::getExt2, bo.getExt2());

        // 根据 type 查询 (映射到 ext2->'$.type')
        if (bo.getType() != null) {
            if (bo.getType() == 2) {
                // 固定路线：明确 type 为 2
                lqw.apply("ext2->'$.type' = 2");
            } else {
                // 普通路线：type 为 1 或 不存在 type 字段
                lqw.apply("(ext2->'$.type' = 1 OR ext2->'$.type' IS NULL)");
            }
        }

        if(params!=null){
            if(params.containsKey("mdate")){
                lqw.ge(params.get("mdate")!=null, TblDzbcPathScheduling::getMdate, (params.get("mdate").toString()));
            }
            if(params.containsKey("carId")){
                lqw.apply(StringUtils.format(" ext1->'$.carInfo.id' = {}", params.get("carId").toString()));
            }

        }

        return lqw;
    }

    /**
     * 新增定制班车-路线排班
     */
    @Override
    public Boolean insertByBo(TblDzbcPathSchedulingBo bo) {
        TblDzbcPathScheduling add = MapstructUtils.convert(bo, TblDzbcPathScheduling.class);
        //添加车辆信息
        Map<String, Object> params = bo.getParams();
        if(add.getCarId()!=null){
           TblDzbcCarVo carVo =  carMapper.selectVoById(bo.getCarId());

           if(carVo == null){
               throw new RuntimeException("车辆不存在");
           }
           if(carVo.getDriverId()==null){
               throw new RuntimeException("该车辆的司机不存在");
           }
            SysUserVo userVo = userMapper.selectUserById(carVo.getDriverId());
            if(userVo==null){
                throw new RuntimeException("该车辆的司机不存在");
            }
            SysUserVo userVo1 = new SysUserVo();
            userVo1.setUserId(userVo.getUserId());
            userVo1.setUserName(userVo.getUserName());
            userVo1.setNickName(userVo.getNickName());
            userVo1.setPhonenumber(userVo.getPhonenumber());
            userVo1.setEmail(userVo.getEmail());
            userVo1.setSex(userVo.getSex());
            if(userVo.getAvatar()!=null){
                userVo1.setAvatarUrl(ossService.selectUrlByIds(userVo.getAvatar().toString()));
            }
            params.put("driverInfo",userVo1);
            params.put("carInfo",carVo);
        }else{
            throw new RuntimeException("车辆不能为空");
        }
        if(add.getPathId()!=null){
            if (bo.getType() != null && bo.getType() == 2) {
                // 固定路线(多站点)
                TblDzbcMultiSitePathVo multiSitePathVo = multiSitePathMapper.selectVoById(bo.getPathId());
                if (multiSitePathVo == null) {
                    throw new RuntimeException("路线不存在");
                }
                params.put("pathInfo", multiSitePathVo);
                // 多站点路线不自动设置mtime，需前端传递或后续处理
            } else {
                // 普通路线
                TblDzbcPathVo pathVo =  pathMapper.selectVoById(bo.getPathId());
                if(pathVo == null){
                    throw new RuntimeException("路线不存在");
                }
                params.put("pathInfo",pathVo);
                // 如果未设置时间，则使用路线默认时间
                if (StrUtil.isBlank(add.getMtime())) {
                    add.setMtime(pathVo.getMtime());
                }
            }
        }else{
            throw new RuntimeException("路线不能为空");
        }
        add.setExt1(JSONUtil.toJsonStr(params));

        // 处理排班类型
        if (bo.getType() != null) {
            JSONObject ext2 = JSONUtil.parseObj(add.getExt2());
            if (ext2 == null) {
                ext2 = JSONUtil.createObj();
            }
            ext2.set("type", bo.getType());
            add.setExt2(ext2.toString());
        }

        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            // 如果是车辆排班(type=2)，自动创建司机发车任务
            if (bo.getType() != null && bo.getType() == 2) {
                createDriverTrip(add, params);
            }
            bo.setId(add.getId());
            SysCache();
        }
        return flag;
    }

    /**
     * 创建司机发车任务
     */
    private void createDriverTrip(TblDzbcPathScheduling scheduling, Map<String, Object> params) {
        try {
            SysUserVo driver = (SysUserVo) params.get("driverInfo");
            if (driver == null) {
                // 如果params中没有，尝试重新查询
                TblDzbcCarVo carVo = carMapper.selectVoById(scheduling.getCarId());
                if (carVo != null && carVo.getDriverId() != null) {
                    driver = userMapper.selectUserById(carVo.getDriverId());
                }
            }

            if (driver != null) {
                TblDzbcDriverTripBo tripBo = new TblDzbcDriverTripBo();
                tripBo.setPathId(scheduling.getPathId());
                tripBo.setDriverId(driver.getUserId());
                tripBo.setCarId(scheduling.getCarId());

                // 设置开始时间 (mdate + mtime)
                String dateStr = DateUtil.formatDate(scheduling.getMdate());
                String timeStr = scheduling.getMtime();
                // 确保时间格式正确，例如 "08:00" -> "08:00:00"
                if (StringUtils.countMatches(timeStr, ":") == 1) {
                    timeStr += ":00";
                }
                String dateTimeStr = dateStr + " " + timeStr;
                LocalDateTime startTime = LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                tripBo.setStartTime(startTime);

                // 扩展字段关联排班ID
                JSONObject ext2 = JSONUtil.createObj();
                ext2.set("schedulingId", scheduling.getId());
                tripBo.setExt2(ext2.toString());

                // 存储排班的 JSON 快照到 ext1
                tripBo.setExt1(JSONUtil.toJsonStr(scheduling));

                driverTripService.createTrip(tripBo);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("自动创建发车任务失败: " + e.getMessage());
        }
    }

    /**
     * 修改定制班车-路线排班
     */
    @Override
    public Boolean updateByBo(TblDzbcPathSchedulingBo bo) {
        // 固定班次(type=2)校验：已发车或完成的不允许修改
        if (bo.getType() != null && bo.getType() == 2 && bo.getId() != null) {
            TblDzbcDriverTrip trip = driverTripMapper.selectOne(
                new LambdaQueryWrapper<TblDzbcDriverTrip>()
                    .apply("ext2->'$.schedulingId' = {0}", bo.getId())
                    .last("LIMIT 1")
            );
            if (trip != null && trip.getStatus() != null && trip.getStatus() >= 1) {
                // status: 0-待发车 1-运行中 2-已完成 3-已取消
                String statusMsg = trip.getStatus() == 1 ? "已发车" : (trip.getStatus() == 2 ? "已完成" : "已取消");
                throw new RuntimeException("该排班" + statusMsg + "，不允许修改");
            }
        }

        TblDzbcPathScheduling update = MapstructUtils.convert(bo, TblDzbcPathScheduling.class);
        validEntityBeforeSave(update);
        int c = baseMapper.updateById(update) ;
        if(c>0){
            Map<String, Object> params = bo.getParams();
            TblDzbcPathScheduling add = baseMapper.selectById(update.getId());
            SysUserVo driverVo = null;
            TblDzbcCarVo carVo = null;
            if(add.getCarId()!=null){
                carVo =  carMapper.selectVoById(bo.getCarId());

                if(carVo == null){
                    throw new RuntimeException("车辆不存在");
                }
                SysUserVo userVo = userMapper.selectUserById(carVo.getDriverId());
                driverVo = new SysUserVo();
                driverVo.setUserId(userVo.getUserId());
                driverVo.setUserName(userVo.getUserName());
                driverVo.setNickName(userVo.getNickName());
                driverVo.setPhonenumber(userVo.getPhonenumber());
                driverVo.setEmail(userVo.getEmail());
                driverVo.setSex(userVo.getSex());
                if(userVo.getAvatar()!=null){
                    driverVo.setAvatarUrl(ossService.selectUrlByIds(userVo.getAvatar().toString()));
                }
                params.put("driverInfo",driverVo);
                params.put("carInfo",carVo);
            }
            if(add.getPathId()!=null){
                if (bo.getType() != null && bo.getType() == 2) {
                    // 固定路线(多站点)
                    TblDzbcMultiSitePathVo multiSitePathVo = multiSitePathMapper.selectVoById(bo.getPathId());
                    if (multiSitePathVo == null) {
                        throw new RuntimeException("路线不存在");
                    }
                    params.put("pathInfo", multiSitePathVo);
                    // 多站点路线不自动设置mtime，需前端传递或后续处理
                } else {
                    // 普通路线
                    TblDzbcPathVo pathVo =  pathMapper.selectVoById(bo.getPathId());
                    if(pathVo == null){
                        throw new RuntimeException("路线不存在");
                    }
                    params.put("pathInfo",pathVo);
                    // 如果未设置时间，则使用路线默认时间
                    if (StrUtil.isBlank(add.getMtime())) {
                        add.setMtime(pathVo.getMtime());
                    }
                }
            }

            // 处理排班类型
            if (bo.getType() != null) {
                JSONObject ext2 = JSONUtil.parseObj(add.getExt2());
                if (ext2 == null) {
                    ext2 = JSONUtil.createObj();
                }
                ext2.set("type", bo.getType());
                add.setExt2(ext2.toString());
            }

            add.setExt1(JSONUtil.toJsonStr(params));
            baseMapper.updateById(add);

            // 固定班次(type=2)修改后，同步更新对应的司机任务
            if (bo.getType() != null && bo.getType() == 2) {
                updateDriverTrip(add, driverVo, carVo);
            }

            SysCache();
        }
        return c> 0;
    }

    /**
     * 更新司机任务（排班修改时同步更新）
     */
    private void updateDriverTrip(TblDzbcPathScheduling scheduling, SysUserVo driver, TblDzbcCarVo carVo) {
        try {
            // 查找该排班关联的司机任务
            TblDzbcDriverTrip trip = driverTripMapper.selectOne(
                new LambdaQueryWrapper<TblDzbcDriverTrip>()
                    .apply("ext2->'$.schedulingId' = {0}", scheduling.getId())
                    .last("LIMIT 1")
            );

            if (trip == null) {
                // 如果不存在司机任务，则创建一个新的
                Map<String, Object> params = new HashMap<>();
                params.put("driverInfo", driver);
                params.put("carInfo", carVo);
                createDriverTrip(scheduling, params);
                return;
            }

            // 如果司机任务已发车或已完成，不允许修改
            if (trip.getStatus() != null && trip.getStatus() >= 1) {
                return;
            }

            // 更新司机任务信息
            TblDzbcDriverTrip updateTrip = new TblDzbcDriverTrip();
            updateTrip.setId(trip.getId());
            updateTrip.setPathId(scheduling.getPathId());

            if (driver != null) {
                updateTrip.setDriverId(driver.getUserId());
                updateTrip.setDriverName(driver.getNickName());
                updateTrip.setDriverPhone(driver.getPhonenumber());
            }

            if (carVo != null) {
                updateTrip.setCarId(carVo.getId());
            }

            // 更新开始时间 (mdate + mtime)
            if (scheduling.getMdate() != null && StrUtil.isNotBlank(scheduling.getMtime())) {
                String dateStr = DateUtil.formatDate(scheduling.getMdate());
                String timeStr = scheduling.getMtime();
                if (StringUtils.countMatches(timeStr, ":") == 1) {
                    timeStr += ":00";
                }
                String dateTimeStr = dateStr + " " + timeStr;
                LocalDateTime startTime = LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                updateTrip.setStartTime(startTime);
            }

            // 更新 ext1 存储排班快照
            updateTrip.setExt1(JSONUtil.toJsonStr(scheduling));

            driverTripMapper.updateById(updateTrip);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



    @Override
    public void SysCache() {
        try {
            ThreadUtil.execAsync(new Runnable() {

                @Override
                public void run() {

                    RedisUtils.deleteKeys("dzbc_path_scheduling*");

                    TblDzbcPathSchedulingBo bo = new TblDzbcPathSchedulingBo();
                    bo.getParams().put("mdate", DateUtil.today());
                    LambdaQueryWrapper<TblDzbcPathScheduling> lqw = buildQueryWrapper(bo);
                    List<TblDzbcPathSchedulingVo> list = baseMapper.selectVoList(lqw);
                    Map<String,Map<String,TblDzbcPathSchedulingVo> > map = new HashMap<>();

                        for (TblDzbcPathSchedulingVo tblDzbcPathSchedulingVo : list) {
                            if(tblDzbcPathSchedulingVo.getMdate()!=null){
                                if(map.containsKey(DateUtil.formatDate(tblDzbcPathSchedulingVo.getMdate()))){
                                    map.get(DateUtil.formatDate(tblDzbcPathSchedulingVo.getMdate())).put(tblDzbcPathSchedulingVo.getId().toString(),tblDzbcPathSchedulingVo);
                                }else{
                                    Map<String,TblDzbcPathSchedulingVo> tempm = new HashMap<>();
                                    tempm.put(tblDzbcPathSchedulingVo.getId().toString(),tblDzbcPathSchedulingVo);
                                    map.put(DateUtil.formatDate(tblDzbcPathSchedulingVo.getMdate()),  tempm);
                                }
                            }
                        }

                    map.keySet().forEach(key ->{
                        RedisUtils.setCacheMap(StrUtil.format("dzbc_path_scheduling|{}", key), map.get(key));
                        RedisUtils.expire(StrUtil.format("dzbc_path_scheduling|{}", key), DateUtil.offset(DateUtil.parseDate(key), DateField.HOUR_OF_DAY, 24).getTime() - DateUtil.current());
                    });
                }
            });

        }catch (Exception e){}


    }


    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(TblDzbcPathScheduling entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除定制班车-路线排班
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        int c =  baseMapper.deleteBatchIds(ids) ;
        if(c>0){
            SysCache();
        }
        return c>0;
    }
}
