package org.dromara.system.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
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.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.CountData;
import org.dromara.system.domain.GpsData;
import org.dromara.system.domain.TblCarSchedule;
import org.dromara.system.domain.bo.CountDataBo;
import org.dromara.system.domain.vo.CountDataVo;
import org.dromara.system.domain.vo.GpsDataVo;
import org.dromara.system.mapper.TblCountDataMapper;
import org.dromara.system.mapper.TblGpsDataMapper;
import org.dromara.system.service.ITblCountDataService;
import org.dromara.util.CamelDataUtil;
import org.dromara.util.MessageUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.dromara.system.domain.bo.TblCarInfoBo;
import org.dromara.system.domain.vo.TblCarInfoVo;
import org.dromara.system.domain.TblCarInfo;
import org.dromara.system.mapper.TblCarInfoMapper;
import org.dromara.system.service.ITblCarInfoService;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 车辆信息Service业务层处理
 *
 * @author Lion Li
 * @date 2024-02-22
 */
@RequiredArgsConstructor
@Service
public class TblCarInfoServiceImpl implements ITblCarInfoService {

    private final TblCarInfoMapper baseMapper;


    private final TblGpsDataMapper gpsDataMapper;

    private final ITblCountDataService countDataMapper;
    /**
     * 查询车辆信息
     */
    @Override
    public TblCarInfoVo queryById(Long id){
        TblCarInfoVo carInfoVo = baseMapper.selectVoById(id);
        try {
            JSONUtil.parseArray(carInfoVo.getDeviceInfos()).toList(JSONObject.class).forEach(deviceInfo -> {
                if(deviceInfo.getStr("type").equals("gps")){
                    carInfoVo.setLocation(RedisUtils.getCacheObject(StringUtils.format("gps_{}", deviceInfo.getStr("code"))));
                }
            });
        }catch (Exception e){}
        return carInfoVo;
    }

    /**
     * 查询车辆信息列表
     */
    @Override
    public TableDataInfo<TblCarInfoVo> queryPageList(TblCarInfoBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<TblCarInfo> lqw = buildQueryWrapper(bo);
        Page<TblCarInfoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);

            result.getRecords().forEach(carInfoVo -> {
                try {
                    JSONUtil.parseArray(carInfoVo.getDeviceInfos()).toList(JSONObject.class).forEach(deviceInfo -> {
                        if (deviceInfo.getStr("type").equals("gps")) {
                            if (RedisUtils.getCacheObject(StringUtils.format("gps_{}", deviceInfo.getStr("code"))) == null) {
                                try {
                                    List<GpsDataVo> d = gpsDataMapper.selectVoPage((new PageQuery()).build(), Wrappers.<GpsData>lambdaQuery().eq(GpsData::getDevicecode, deviceInfo.getStr("code")).orderByDesc(GpsData::getTs));
                                    if (d != null && d.size() > 0) {
                                        carInfoVo.setLocation(d.get(0));
                                    }
                                } catch (Exception e) {
                                }
                            } else {
                                carInfoVo.setLocation(RedisUtils.getCacheObject(StringUtils.format("gps_{}", deviceInfo.getStr("code"))));
                            }
                        }
                        if (deviceInfo.getStr("type").equals("people_count")) {
                            carInfoVo.setLastCountTime(RedisUtils.getCacheObject(StringUtils.format("count_{}", deviceInfo.getStr("code"))));
                        }
                    });
                }catch (Exception e){}
            });


        return TableDataInfo.build(result);
    }

    /**
     * 查询车辆信息列表
     */
    @Override
    public List<TblCarInfoVo> queryList(TblCarInfoBo bo) {
        LambdaQueryWrapper<TblCarInfo> lqw = buildQueryWrapper(bo);
        List<TblCarInfoVo> list =baseMapper.selectVoList(lqw);
        list.forEach(carInfoVo -> {
            carInfoVo.setLocation(RedisUtils.getCacheObject(StringUtils.format("gps_{}", carInfoVo.getId())));
        });
        return list;
    }

    @Override
    public TableDataInfo<TblCarInfoVo> queryFlowList(TblCarInfoBo bo, PageQuery pageQuery){
        LambdaQueryWrapper<TblCarInfo> lqw = buildQueryWrapper(bo);
        Page<TblCarInfoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        List<String> codes = new ArrayList<>();
        result.getRecords().forEach(carInfoVo -> {
            JSONUtil.parseArray(carInfoVo.getDeviceInfos()).toList(JSONObject.class).forEach(deviceInfo -> {
                try {
                    if(deviceInfo.getStr("type").equals("people_count")){
                        codes.add( deviceInfo.getStr("code"));
                    }
                }catch (Exception e){}

            });
        });
        Map<String,List<CountDataVo>> countDataMap = new HashMap<>();
        //查流量
        if(codes.size()>0){
            codes.forEach(code->{
                CountDataBo q = new CountDataBo();
                q.setParams(bo.getParams());
                q.getParams().put("deviceCodes",code);
                List<CountDataVo> countDataList = countDataMapper.queryList(q);
                if(countDataList.size()>0){
                    countDataList.forEach(countData -> {
                        if(countDataMap.get(countData.getDevicecode())==null){
                            List<CountDataVo> countDataList1 = new ArrayList<>();
                            countDataList1.add(countData);
                            countDataMap.put(countData.getDevicecode(),countDataList1);
                        }else{
                            countDataMap.get(countData.getDevicecode()).add(countData);
                        }
                    });
                }

            });

        }
        try {

            result.getRecords().forEach(carInfoVo -> {
                carInfoVo.setOthers(new HashMap<>());
                carInfoVo.getOthers().put("incount",0);
                carInfoVo.getOthers().put("outcount",0);
                JSONUtil.parseArray(carInfoVo.getDeviceInfos()).toList(JSONObject.class).forEach(deviceInfo -> {
                    if(deviceInfo.getStr("type").equals("people_count")){
                        if(countDataMap.get(deviceInfo.getStr("code"))!=null && countDataMap.get(deviceInfo.getStr("code")).size()>0){
                            List<CountDataVo> countDataList = countDataMap.get(deviceInfo.getStr("code"));
                            if(countDataList.size()>0){
                                countDataList.stream().reduce((a,b)->{a.setIncount(a.getIncount()+b.getIncount());a.setOutcount(a.getOutcount()+b.getOutcount());return a;});
                                carInfoVo.getOthers().put("incount",countDataList.get(0).getIncount());
                                carInfoVo.getOthers().put("outcount",countDataList.get(0).getOutcount());
                            }
                        }
                    }
                });
            });
        }catch (Exception e){}

        return TableDataInfo.build(result);
    }

    private LambdaQueryWrapper<TblCarInfo> buildQueryWrapper(TblCarInfoBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<TblCarInfo> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getId()!=null, TblCarInfo::getId, bo.getId());
        lqw.eq(StringUtils.isNotBlank(bo.getCarNum()), TblCarInfo::getCarNum, bo.getCarNum());
        lqw.eq(StringUtils.isNotBlank(bo.getCarType()), TblCarInfo::getCarType, bo.getCarType());
        lqw.like(StringUtils.isNotBlank(bo.getDeviceInfos()), TblCarInfo::getDeviceInfos, bo.getDeviceInfos());
//        lqw.eq(StringUtils.isNotBlank(bo.getDeviceInfos()), TblCarInfo::getDeviceInfos, bo.getDeviceInfos());
        lqw.eq(StringUtils.isNotBlank(bo.getRepairInfo()), TblCarInfo::getRepairInfo, bo.getRepairInfo());
        lqw.eq(StringUtils.isNotBlank(bo.getMaintenanceInfo()), TblCarInfo::getMaintenanceInfo, bo.getMaintenanceInfo());
        lqw.eq(StringUtils.isNotBlank(bo.getInsuranceInfo()), TblCarInfo::getInsuranceInfo, bo.getInsuranceInfo());
        lqw.eq(StringUtils.isNotBlank(bo.getInspectionInfo()), TblCarInfo::getInspectionInfo, bo.getInspectionInfo());
        lqw.eq(StringUtils.isNotBlank(bo.getTrafficAccidentInfo()), TblCarInfo::getTrafficAccidentInfo, bo.getTrafficAccidentInfo());
        lqw.eq(StringUtils.isNotBlank(bo.getViolationInfo()), TblCarInfo::getViolationInfo, bo.getViolationInfo());
        lqw.eq(StringUtils.isNotBlank(bo.getChangeInfo()), TblCarInfo::getChangeInfo, bo.getChangeInfo());

        if(bo.getParams()!=null && bo.getParams().get("carNums")!=null){
            String carNums = (String) ((List)bo.getParams().get("carNums")).stream().map(carnum->{return StrUtil.format("'{}'",carnum); }).collect(Collectors.joining(","));

            lqw.apply(StringUtils.format("car_num in ({})",carNums));

        }

        if(bo.getParams()!=null && bo.getParams().size()>0){
            if(bo.getParams().get("depts")!=null&& StrUtil.isNotEmpty(bo.getParams().get("depts").toString())){
                String deptids = Arrays.stream(bo.getParams().get("depts").toString().split(",")).map(deptId->{return StrUtil.format("'{}'",deptId); }).collect(Collectors.joining(","));
                lqw.apply(StringUtils.format("ext1->'$.{}' in ({})","deptId",deptids));
            }
        }
//        if(LoginHelper.getDeptId())

        //lqw.eq(StringUtils.isNotBlank(bo.getExt1()), TblCarInfo::getExt1, bo.getExt1());
        //lqw.eq(StringUtils.isNotBlank(bo.getExt2()), TblCarInfo::getExt2, bo.getExt2());
        if(bo.getParams()!=null){
            if(bo.getParams().keySet().size()>0){
                for (String key:bo.getParams().keySet()) {
                    if(key.contains("ext1")){
                        lqw.apply(StringUtils.format("ext1->'$.{}'='{}'",key.split("\\$")[1],bo.getParams().get(key)));
                    }
                    if(key.contains("ext2")){
                        lqw.apply(StringUtils.format("ext2->'$.{}'='{}'",key.split("\\$")[1],bo.getParams().get(key)));
                    }
                    if(key.contains("ext2")){
                        lqw.apply(StringUtils.format("ext2->'$.{}'='{}'",key.split("\\$")[1],bo.getParams().get(key)));
                    }
                }
            }
        }

        if(bo.getParams()!=null && bo.getParams().get("driverInfo")!=null){
            lqw.apply(StringUtils.format("ext2->'$.driverInfo'={}",bo.getParams().get("driverInfo")));
//            lqw.like(bo.getParams().get("driverInfo")!=null, TblCarInfo::getExt2, bo.getParams().get("driverInfo"));
        }


        return lqw;
    }

    /**
     * 新增车辆信息
     */
    @Override
    public Boolean insertByBo(TblCarInfoBo bo) {
        TblCarInfo add = MapstructUtils.convert(bo, TblCarInfo.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改车辆信息
     */
    @Override
    public Boolean updateByBo(TblCarInfoBo bo) {
        TblCarInfo update = MapstructUtils.convert(bo, TblCarInfo.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

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

    /**
     * 批量删除车辆信息
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }
}
