package com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson2.JSONObject;
import com.cico.nest.lcdp.boot.core.qxsd.adapter.web.request.LocusDataRequest;
import com.cico.nest.lcdp.boot.core.qxsd.adapter.web.request.PassingProfileRequest;
import com.cico.nest.lcdp.boot.core.qxsd.adapter.web.vo.PassProfileImageVO;
import com.cico.nest.lcdp.boot.core.qxsd.adapter.web.vo.PassingProfileVO;
import com.cico.nest.lcdp.boot.core.qxsd.adapter.ws.*;
import com.cico.nest.lcdp.boot.core.qxsd.domain.gateway.VehicleGateway;
import com.cico.nest.lcdp.boot.core.qxsd.domain.vehicle.HistoryTunnelVehicle;
import com.cico.nest.lcdp.boot.core.qxsd.domain.vehicle.TunnelRealTimeVehicle;
import com.cico.nest.lcdp.boot.core.qxsd.domain.vehicle.VehicleInfo;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.common.constatnt.RedisConstants;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.common.constatnt.XlwConstants;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.common.result.XlwResultData;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.convertor.VehicleConvertor;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.TunnelDetailMapper;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.dataobject.TunnelDetailDO;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.http.xlw.dto.*;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.http.xlw.feign.XlwClientFeign;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.ws.xlw.RealTimeVehicleWsClient;
import com.cico.nest.lcdp.framework.common.exception.ServiceException;
import com.cico.nest.lcdp.framework.common.pojo.PageResult;
import com.cico.nest.lcdp.framework.common.util.json.JsonUtils;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.cico.nest.lcdp.boot.api.infra.enums.ErrorCodeConstants.CODEGEN_TABLE_EXISTS;
import static com.cico.nest.lcdp.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
import static com.cico.nest.lcdp.framework.common.exception.util.ServiceExceptionUtil.exception;

/**
 * @author zws
 * @date 2024/8/5
 */
@Slf4j
@Service
public class VehicleGatewayImpl implements VehicleGateway {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private XlwClientFeign xlwClientFeign;

    @Resource
    private TunnelDetailMapper tunnelDetailMapper;

    public final Map<String, IRealTimeWs> realTimeWsMap = new ConcurrentHashMap<>();

    @Override
    public void pushRealTimeVehicleData(TunnelRealTimeVehicle realTimeVehicle,String tunnelId) {
        IRealTimeWs realTimeWs = getRealTimeWs(tunnelId);
        Set<String> keys = stringRedisTemplate.keys(RedisConstants.REDIS_FOCUS_VEHICLE_MARK_KEY.concat("*"));
        if(Objects.isNull(keys)){
            String realTimeVehicleJson = JSONObject.toJSONString(realTimeVehicle);
            stringRedisTemplate.opsForValue().set(RedisConstants.REDIS_REAL_TIME_VEHICLE_KEY.concat(tunnelId),realTimeVehicleJson,10, TimeUnit.SECONDS);
            realTimeWs.sendMessage(realTimeVehicleJson);
            return;
        }
        List<VehicleInfo> vehicleInfoList = realTimeVehicle.getVehicleInfoList();
        List<String> realTimeVehicleCarIds = vehicleInfoList.stream().map(VehicleInfo::getCarId).toList();
        List<String> redisMrkVehicleCarIds = stringRedisTemplate.opsForValue().multiGet(keys);

        //取交集(当前重点标记的车辆)
        Set<String> currentMarkCarIds = CollUtil.intersectionDistinct(realTimeVehicleCarIds,redisMrkVehicleCarIds);
        if(CollUtil.isNotEmpty(currentMarkCarIds)){
            for(VehicleInfo vehicleInfo : vehicleInfoList){
                if(currentMarkCarIds.contains(vehicleInfo.getCarId())){
                    vehicleInfo.setIsFocusMark(true);
                }
            }
        }
//        //取差集(删除标记缓存)
//        List<String> delRedisMarkKey = CollUtil.subtractToList(redisMrkVehicleCarIds,realTimeVehicleCarIds);
//        delRedisMarkKey = delRedisMarkKey.stream()
//                .map(RedisConstants.REDIS_FOCUS_VEHICLE_MARK_KEY::concat)
//                .collect(Collectors.toList());
//        stringRedisTemplate.delete(delRedisMarkKey);

        String realTimeVehicleJson = JSON.toJSONString(realTimeVehicle,SerializerFeature.WriteMapNullValue);
        stringRedisTemplate.opsForValue().set(RedisConstants.REDIS_REAL_TIME_VEHICLE_KEY.concat(tunnelId),realTimeVehicleJson,10, TimeUnit.SECONDS);
        realTimeWs.sendMessage(realTimeVehicleJson);
    }

    @Override
    public PageResult<PassingProfileVO> passingProfileList(PassingProfileRequest request) {
        XlwPassingProfileSearchDTO searchDTO = new XlwPassingProfileSearchDTO();
        searchDTO.setPage(request.getPageNo());
        searchDTO.setPageSize(request.getPageSize());
        searchDTO.setEntityName(request.getCarPlate());
        searchDTO.setCarTypeList(request.getCarType());
        searchDTO.setFirstStartTime(request.getFirstStartTime());
        searchDTO.setFirstEndTime(request.getFirstEndTime());
        if(Objects.nonNull(request.getStDurationSecond())){
            searchDTO.setDurationSecond(request.getStDurationSecond() * 60);
        }
        if(Objects.nonNull(request.getEdDurationSecond())){
            searchDTO.setEdDurationSecond(request.getEdDurationSecond() * 60);
        }
        searchDTO.setPassProfileId(request.getPassProfileId());
        searchDTO.setStAvgSpeed(request.getStAvgSpeed());
        searchDTO.setEdAvgSpeed(request.getEdAvgSpeed());
        if(StrUtil.isNotEmpty(request.getKeyword())){
            Map<String, Object> orQueryMap = new HashMap<>();
            orQueryMap.put("car_type",request.getKeyword());     //车辆类型
            orQueryMap.put("entity_name",request.getKeyword());  //车牌号码
            //orQueryMap.put("tunnel_id",request.getKeyword());    //方向
            searchDTO.setOrQueryMap(orQueryMap);
        }
        if(CollUtil.isNotEmpty(request.getDirection()) && request.getDirection().size() == 1){
            for(String direction : request.getDirection()){
                if("上行".equals(direction)){
                    searchDTO.setTunnelId("tunnel_up");
                }else if("下行".equals(direction)){
                    searchDTO.setTunnelId("tunnel_down");
                }
            }
        }
        XlwResultData<XlwPageDTO<XlwPassingProfileDTO>> resultData = xlwClientFeign.getPassingProfile(searchDTO);
        PageResult<PassingProfileVO> pageResult = new PageResult<>();
        if (resultData.getData()!=null) {
            XlwPageDTO<XlwPassingProfileDTO> pageData = resultData.getData();
            List<XlwPassingProfileDTO> xlwPassingProfileDTOS = pageData.getRows();
            pageResult.setList(XlwPassingProfileDTO.toVOList(xlwPassingProfileDTOS));
            pageResult.setTotal(pageData.getTotal());
        }
        return pageResult;
    }

    @Override
    public PassProfileImageVO passProfileImage(String passProfileId) {
        XlwPassProfileIdDTO xlwPassProfileIdDTO = new XlwPassProfileIdDTO();
        xlwPassProfileIdDTO.setPassProfileId(passProfileId);
        XlwResultData<List<XlwPassProfileImageDTO>> resultData = xlwClientFeign.getPassProfileImage(xlwPassProfileIdDTO);
        XlwPassProfileImageDTO dto = resultData.getData().get(0);
        return XlwPassProfileImageDTO.toVO(dto);
    }

    @Override
    public Map<String, PassProfileImageVO> passProfileImageList(List<String> passProfileIds) {
        Map<String,List<String>> requestBody = new HashMap<>();
        requestBody.put("passProfileIdList",passProfileIds);
        XlwResultData<List<Map<String,Object>>> resultData = xlwClientFeign.getPassProfileImage(requestBody);
        List<Map<String,Object>> imageDto = resultData.getData();
        Map<String, PassProfileImageVO> imageVO = new HashMap<>();
        for(Map<String,Object> map : imageDto){
            String trackId = (String) map.get("trackId");
            List<XlwPassProfileImageDTO> passProfileImageDTOS = JSON.parseArray(JSON.toJSONString( map.get("sectionList")),XlwPassProfileImageDTO.class);
            for(XlwPassProfileImageDTO dto : passProfileImageDTOS){
                if("入".equals(dto.getPositionMark())){
                    imageVO.put(trackId,XlwPassProfileImageDTO.toVO(dto)) ;
                    break;
                }
            }
        }
        return imageVO;
    }

    @Override
    public List<HistoryTunnelVehicle> getCarLocusData(LocusDataRequest request) {
        XlwLocusDataSearchDTO searchDTO = new XlwLocusDataSearchDTO();
        searchDTO.setTunnelId(request.getTunnelId());
        searchDTO.setStartTime(request.getStartTime());
        searchDTO.setEndTime(request.getEndTime());
        XlwResultData<List<XlwHolographicTimeHistoryDTO>> resultData = xlwClientFeign.getCarLocusData(searchDTO);
        if(CollectionUtils.isEmpty(resultData.getData())){
            log.error("调用4.5接口获取车辆轨迹数据为空，参数:{}", JsonUtils.toJsonString(searchDTO));
            log.error("调用4.5接口获取车辆轨迹数据为空，返回值:{}", resultData.getMessage());
            return new ArrayList<>();
        }
        List<XlwHolographicTimeHistoryDTO> dtos = resultData.getData();
        TunnelDetailDO tunnelDetailDO = tunnelDetailMapper.selectById(request.getTunnelId());
        dtos = dtos.stream().filter(s->tunnelDetailDO.getXlwTunnelId().equals(s.getTunnelId())).toList();
        return VehicleConvertor.convert2HistoryTunnelVehicle(dtos,request.getTunnelId(),tunnelDetailDO.getDirection(),tunnelDetailDO.getStartMilestone());
    }

    public IRealTimeWs getRealTimeWs(String tunnelId){
        IRealTimeWs realTimeWs = realTimeWsMap.get(tunnelId);
        if(Objects.isNull(realTimeWs)){
            Map<String, AbstractRealTimeVehicleWs> beansOfType = SpringUtil.getBeansOfType(AbstractRealTimeVehicleWs.class);
            if(CollUtil.isNotEmpty(beansOfType)){
                for(Map.Entry<String, AbstractRealTimeVehicleWs> entry : beansOfType.entrySet()){
                    AbstractRealTimeVehicleWs abstractRealTimeVehicleWs = entry.getValue();
                    realTimeWsMap.put(abstractRealTimeVehicleWs.tunnelId(),abstractRealTimeVehicleWs);
                }
            }
        }
        return realTimeWsMap.get(tunnelId);
    }
}
