package com.gci.boot.modules.gis.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gci.boot.common.util.JsonUtil;
import com.gci.boot.common.util.LatLonPoint;
import com.gci.boot.common.util.RedisUtil;
import com.gci.boot.constant.CacheConstant;
import com.gci.boot.constant.CommonConstant;
import com.gci.boot.exception.GciBootException;
import com.gci.boot.modules.basedata.entity.TbVehicle;
import com.gci.boot.modules.basedata.service.ITbVehicleService;
import com.gci.boot.modules.gis.entity.TbGisFenceInfo;
import com.gci.boot.modules.gis.entity.TbGisFencePlan;
import com.gci.boot.modules.gis.entity.TbGisFenceVehicle;
import com.gci.boot.modules.gis.mapper.TbGisFencePlanMapper;
import com.gci.boot.modules.gis.service.ITbGisFenceInfoService;
import com.gci.boot.modules.gis.service.ITbGisFencePlanService;
import com.gci.boot.modules.gis.service.ITbGisFenceVehicleService;
import com.gci.boot.modules.gis.vo.GisProjectTreeVo;
import com.gci.boot.modules.gis.vo.GisRedisVehicleVo;
import com.gci.boot.modules.gis.vo.GisVehicleVo;
import com.gci.boot.modules.projects.entity.Projects;
import com.gci.boot.modules.projects.service.IProjectsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 围栏方案表 服务实现类
 * </p>
 *
 * @author 2464
 * @since 2023-08-30
 */
@Service
public class TbGisFencePlanServiceImpl extends ServiceImpl<TbGisFencePlanMapper, TbGisFencePlan> implements ITbGisFencePlanService {

    @Resource
    private TbGisFencePlanMapper fencePlanMapper;
    @Autowired
    private ITbGisFenceInfoService fenceInfoService;
    @Autowired
    private ITbGisFenceVehicleService fenceVehicleService;
    @Autowired
    private IProjectsService projectsService;
    @Autowired
    private ITbVehicleService vehicleService;

    @Override
    public void saveItem(TbGisFencePlan tbGisFencePlan) {
        checkTime(tbGisFencePlan);
        String projectId = tbGisFencePlan.getProjectId();
        Projects byId = projectsService.getById(projectId);
        if (BeanUtil.isEmpty(byId) || byId.getCancelFlag() == 1) {
            throw new GciBootException("该项目不存在或者已经禁用，请重新选择项目！");
        }
        save(tbGisFencePlan);
        List<TbGisFenceInfo> gisFenceInfoList = tbGisFencePlan.getGisFenceInfoList();
        gisFenceInfoList.forEach(i -> {
            i.setPlanId(tbGisFencePlan.getId());
            i.setPlanName(tbGisFencePlan.getName());
        });
        fenceInfoService.saveBatch(gisFenceInfoList);
        findAndUpdateVehicleRedis(tbGisFencePlan.getId());
    }

    /**
     * 校验时间先后
     *
     * @param tbGisFencePlan
     */
    private void checkTime(TbGisFencePlan tbGisFencePlan) {
        String startTime = tbGisFencePlan.getStartTime();
        String endTime = tbGisFencePlan.getEndTime();
        DateTime start = DateUtil.parse(startTime);
        DateTime end = DateUtil.parse(endTime);
        if (tbGisFencePlan.getIsOvernight() == 0) {
            if (DateUtil.between(start, end, DateUnit.MINUTE, false) < 0) {
                throw new GciBootException("开始时间不能大于结束时间");
            }
        } else {
            long between = DateUtil.between(start, DateUtil.offset(end, DateField.DAY_OF_MONTH, 1), DateUnit.HOUR);
            if (between > 24) {
                throw new GciBootException("时间间隔不能超过24小时");
            }
        }
    }

    @Override
    public void updateItem(TbGisFencePlan tbGisFencePlan) {
        checkTime(tbGisFencePlan);
        String projectId = tbGisFencePlan.getProjectId();
        Projects byId = projectsService.getById(projectId);
        if (BeanUtil.isEmpty(byId) || byId.getCancelFlag() == 1) {
            throw new GciBootException("该项目不存在或者已经禁用，请重新选择项目！");
        }
        updateById(tbGisFencePlan);
        //清空旧的在保存新的
        fenceInfoService.remove(new LambdaQueryWrapper<TbGisFenceInfo>().eq(TbGisFenceInfo::getPlanId, tbGisFencePlan.getId()));
        List<TbGisFenceInfo> gisFenceInfoList = tbGisFencePlan.getGisFenceInfoList();
        gisFenceInfoList.forEach(i -> {
            i.setPlanId(tbGisFencePlan.getId());
            i.setPlanName(tbGisFencePlan.getName());
        });
        fenceInfoService.saveBatch(gisFenceInfoList);
        findAndUpdateVehicleRedis(tbGisFencePlan.getId());
    }

    @Override
    public void saveVehicle(GisVehicleVo vo) {
        checkVehicle(vo.getVehicleList());

        saveFenceVehicle(vo);
    }

    /**
     * 检查是否已有车辆
     *
     * @param vehicleList
     */
    private void checkHadVehicle(GisVehicleVo vehicleList) {
        LambdaQueryWrapper<TbGisFenceVehicle> in = new LambdaQueryWrapper<TbGisFenceVehicle>().in(TbGisFenceVehicle::getPlateNumber, vehicleList.getVehicleList()).eq(TbGisFenceVehicle::getPlanId,vehicleList.getPlanId());
        int count = fenceVehicleService.count(in);
        if (count > 0) {
            throw new GciBootException("已有对应关联车辆！");
        }
    }

    @Override
    public void delVehicle(GisVehicleVo vo) {
        checkVehicle(vo.getVehicleList());
        delFenceVehicle(vo);
    }

    @Override
    public void isValid(String id) {
        TbGisFencePlan gisFencePlan = getById(id);

        gisFencePlan.setIsValid(1);
        updateById(gisFencePlan);
        //车辆列表
        findAndUpdateVehicleRedis(id);
    }

    /**
     * 根据方案id更新车辆redis
     *
     * @param id
     */
    private void findAndUpdateVehicleRedis(String id) {
        LambdaQueryWrapper<TbGisFenceVehicle> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TbGisFenceVehicle::getPlanId, id);
        List<TbGisFenceVehicle> gisFenceVehicleList = fenceVehicleService.list(wrapper);
        if (ObjectUtil.isNotEmpty(gisFenceVehicleList)) {
            updateVehicleRedis(gisFenceVehicleList);
        }
    }

    @Override
    public void unValid(String id) {
        TbGisFencePlan gisFencePlan = getById(id);
        gisFencePlan.setIsValid(0);
        updateById(gisFencePlan);
        //车辆列表
        findAndUpdateVehicleRedis(id);
    }

    @Override
    public Page<TbVehicle> getPlanVehicleList(String id, Page<TbVehicle> page) {
        List<TbGisFenceVehicle> list = fenceVehicleService.list(new LambdaQueryWrapper<TbGisFenceVehicle>().eq(TbGisFenceVehicle::getPlanId, id));
        if (ObjectUtil.isNotEmpty(list)) {
            return vehicleService.page(page,new LambdaQueryWrapper<TbVehicle>().in(TbVehicle::getPlateNumber, list.stream().map(TbGisFenceVehicle::getPlateNumber).collect(Collectors.toList())).eq(TbVehicle::getCancelFlag, 0));
        }
        return page;
    }

    @Override
    public List<GisProjectTreeVo> getProjectVehicleList(String id) {
        TbGisFencePlan byId = getById(id);
        List<GisProjectTreeVo> gisProjectTreeVos = new ArrayList<>();
        if (ObjectUtil.isEmpty(byId)) {
            return gisProjectTreeVos;
        }
        List<TbVehicle> list = vehicleService.list(new LambdaQueryWrapper<TbVehicle>().eq(TbVehicle::getProjectId, byId.getProjectId()).eq(TbVehicle::getCancelFlag, 0));
        Map<String, List<TbVehicle>> collect = list.stream().collect(Collectors.groupingBy(TbVehicle::getProjectId));

        if (ObjectUtil.isEmpty(collect)) {
            return gisProjectTreeVos;
        }
        List<Projects> projectsList = projectsService.list(new LambdaQueryWrapper<Projects>().in(Projects::getId, collect.keySet()).eq(Projects::getCancelFlag,0));
        for (Projects projects : projectsList) {
            GisProjectTreeVo gisProjectTreeVo = new GisProjectTreeVo();
            gisProjectTreeVo.setProjectId(projects.getId());
            gisProjectTreeVo.setProjectName(projects.getProjectName());
            gisProjectTreeVo.setVehicleList(collect.get(projects.getId()));
            List<TbGisFenceVehicle> list1 = fenceVehicleService.list(new LambdaQueryWrapper<TbGisFenceVehicle>().eq(TbGisFenceVehicle::getPlanId, id));
            if (ObjectUtil.isNotEmpty(list1)){
                gisProjectTreeVo.setHadBind(list1.stream().map(TbGisFenceVehicle::getPlateNumber).collect(Collectors.toList()));
            }
            gisProjectTreeVos.add(gisProjectTreeVo);
        }
        return gisProjectTreeVos;
    }

    @Override
    public List<TbGisFenceInfo> getPlanFenceInfoList(String id) {
        LambdaQueryWrapper<TbGisFenceInfo> eq = new LambdaQueryWrapper<TbGisFenceInfo>().eq(TbGisFenceInfo::getPlanId, id);
        return fenceInfoService.list(eq);
    }

    @Override
    public void updateAll() {
        List<TbGisFenceVehicle> list = fenceVehicleService.list();
        delAllVehicleRedis();
        updateVehicleRedis(list);
    }

    private void delAllVehicleRedis() {
        Set<String> scan = RedisUtil.getScan(CacheConstant.VEHICLE_FENCE_KEY + "*");
        RedisUtil.multiDel(scan);
    }

    /**
     * 删除车辆并更新redis数据
     */
    private void delFenceVehicle(GisVehicleVo vo) {
        fenceVehicleService.remove(new LambdaQueryWrapper<TbGisFenceVehicle>().eq(TbGisFenceVehicle::getPlanId, vo.getPlanId()).in(TbGisFenceVehicle::getPlateNumber, vo.getVehicleList()));
//        delVehicleRedis(vo);
        ArrayList<TbGisFenceVehicle> gisVehicleVos = new ArrayList<>();
        List<String> vehicleList = vo.getVehicleList();
        for (String s : vehicleList) {
            TbGisFenceVehicle tbGisFenceVehicle = new TbGisFenceVehicle();
            tbGisFenceVehicle.setPlateNumber(s);
            gisVehicleVos.add(tbGisFenceVehicle);
        }
        updateVehicleRedis(gisVehicleVos);
    }

    /**
     * 删除Redis数据
     */
    private void delVehicleRedis(GisVehicleVo vo) {
        List<String> vehicleList = vo.getVehicleList();
        for (String s : vehicleList) {
            RedisUtil.del(CacheConstant.VEHICLE_FENCE_KEY + s);
        }
    }

    /**
     * 新增车辆并同步redis数据
     */
    private void saveFenceVehicle(GisVehicleVo vo) {
        List<String> vehicleList = vo.getVehicleList();

        List<TbGisFenceVehicle> list = fenceVehicleService.list(new LambdaQueryWrapper<TbGisFenceVehicle>().eq(TbGisFenceVehicle::getPlanId, vo.getPlanId()));
        if (ObjectUtil.isNotEmpty(list)) {
            vehicleList = CollUtil.subtractToList(vehicleList,list.stream().map(TbGisFenceVehicle::getPlateNumber).collect(Collectors.toList()));
        }
        if (vehicleList.size() == 0) {
            return;
        }
        ArrayList<TbGisFenceVehicle> gisVehicleVos = new ArrayList<>();
        List<TbVehicle> tbVehicleList = vehicleService.list(new LambdaQueryWrapper<TbVehicle>().in(TbVehicle::getPlateNumber, vehicleList).eq(TbVehicle::getCancelFlag, CommonConstant.DEL_FLAG_0));
        for (TbVehicle vehicle : tbVehicleList) {
            TbGisFenceVehicle tbGisFenceVehicle = new TbGisFenceVehicle();
            tbGisFenceVehicle.setPlanId(vo.getPlanId());
            tbGisFenceVehicle.setPlateNumber(vehicle.getPlateNumber());
            gisVehicleVos.add(tbGisFenceVehicle);
            tbGisFenceVehicle.setGpsNo(vehicle.getLocationTerminalId());
        }
        fenceVehicleService.saveBatch(gisVehicleVos);
        updateVehicleRedis(gisVehicleVos);
    }

    /**
     * 更新redis缓存数据
     *
     * @param gisVehicleVos
     */
    private void updateVehicleRedis(List<TbGisFenceVehicle> gisVehicleVos) {
        HashMap<String, Object> stringObjectHashMap = new HashMap<>(10);
        //这辆车可能在多个方案内
        List<GisRedisVehicleVo> gisFenceInfoList = fencePlanMapper.getGisFenceInfoList(gisVehicleVos.stream().map(TbGisFenceVehicle::getPlateNumber).collect(Collectors.toList()));
        if (ObjectUtil.isNotEmpty(gisFenceInfoList)) {
            for (GisRedisVehicleVo gisRedisVehicleVo : gisFenceInfoList) {
                if (StrUtil.isBlank(gisRedisVehicleVo.getPlateNumber())) {
                    continue;
                }
                RedisUtil.del(CacheConstant.VEHICLE_FENCE_KEY + gisRedisVehicleVo.getPlateNumber());
                ArrayList<LatLonPoint> latLonPoints = new ArrayList<>();
                JSONArray objects = JSONUtil.parseArray(gisRedisVehicleVo.getGeoJson());
                for (Object object : objects) {
                    LatLonPoint latLonPoint = new LatLonPoint();
                    JSONArray objects1 = JSONUtil.parseArray(object);
                    latLonPoint.setLongitude(Convert.toDouble(objects1.get(0)));
                    latLonPoint.setLatitude(Convert.toDouble(objects1.get(1)));
                    latLonPoints.add(latLonPoint);
                }
                gisRedisVehicleVo.setCoordinateList(latLonPoints);
            }
            Map<String, List<GisRedisVehicleVo>> collect = gisFenceInfoList.stream().filter(i->StrUtil.isNotBlank(i.getPlateNumber())).collect(Collectors.groupingBy(GisRedisVehicleVo::getPlateNumber));
            for (TbGisFenceVehicle gisVehicleVo : gisVehicleVos) {
                String key = CacheConstant.VEHICLE_FENCE_KEY + gisVehicleVo.getPlateNumber();
                List<GisRedisVehicleVo> gisRedisVehicleVos = collect.get(gisVehicleVo.getPlateNumber());
                if (ObjectUtil.isNotEmpty(gisRedisVehicleVos)) {
                    stringObjectHashMap.put(key, JsonUtil.object2Json(gisRedisVehicleVos));
                }
            }
            if (ObjectUtil.isNotEmpty(stringObjectHashMap)) {
                RedisUtil.multiSet(stringObjectHashMap);
            }
        }
    }


    /**
     * 检查车牌号是否正常
     *
     * @param vehicleList
     */
    private void checkVehicle(List<String> vehicleList) {
        StringBuilder stringBuilder = new StringBuilder();
        ArrayList<String> strings = new ArrayList<>();
        for (String s : vehicleList) {
            boolean plateNumber = ReUtil.isMatch("^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-HJ-NP-Z][A-HJ-NP-Z0-9]{4,5}[A-HJ-NP-Z0-9挂学警港澳]$", s);
            if (!plateNumber) {
                stringBuilder.append(s).append("格式错误！");
            } else {
                strings.add(s);
            }
        }
        if (ObjectUtil.isNotEmpty(strings)) {
            List<TbVehicle> list = vehicleService.list(new LambdaQueryWrapper<TbVehicle>().in(TbVehicle::getPlateNumber, strings).eq(TbVehicle::getCancelFlag, CommonConstant.DEL_FLAG_0));
            if (list.size() != strings.size() || list == null) {
                List<String> subtract = CollUtil.subtractToList(strings, list.stream().map(TbVehicle::getPlateNumber).collect(Collectors.toList()));
                stringBuilder.append(subtract).append("车辆不存在！");
            }
        }
        if (StrUtil.isNotBlank(stringBuilder)) {
            throw new GciBootException(stringBuilder.toString());
        }
    }
}
