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

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.cico.nest.lcdp.boot.core.qxsd.application.service.EventDetailService;
import com.cico.nest.lcdp.boot.core.qxsd.application.service.HistoryService;
import com.cico.nest.lcdp.boot.core.qxsd.application.service.TunnelBaseService;
import com.cico.nest.lcdp.boot.core.qxsd.application.service.TunnelDetailService;
import com.cico.nest.lcdp.boot.core.qxsd.application.service.TunnelHoleService;
import com.cico.nest.lcdp.boot.core.qxsd.domain.event.EventSource;
import com.cico.nest.lcdp.boot.core.qxsd.domain.event.EventTypeAllEnum;
import com.cico.nest.lcdp.boot.core.qxsd.domain.gateway.EventGateway;
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.gatewayimpl.database.EventDetailMapper;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.dataobject.EventDetailDO;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.dataobject.TunnelBaseDO;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.dataobject.TunnelDetailDO;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.dataobject.TunnelHoleV2DO;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.http.xlw.XlwAuthMapper;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.ws.xlw.dto.XlwRealTimeEventDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHttpHeaders;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.net.URI;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author zws
 * 对接信路威实时事件接口
 * @date 2024/8/14
 */
@Component
@Slf4j
public class RealTimeEventWsClient {

    @Resource
    private XlwAuthMapper xlwAuthMapper;
    @Resource
    private EventDetailMapper eventDetailMapper;
    @Resource
    private EventDetailService eventDetailService;
    @Resource
    private EventGateway eventGateway;

    @Resource
    private TunnelBaseService tunnelBaseService;

    @Resource
    private TunnelDetailService tunnelDetailService;
    @Resource
    private TunnelHoleService tunnelHoleService;
    @Resource
    private HistoryService historyService;

    private final ExecutorService service = Executors.newFixedThreadPool(5);

    public void connectAndHandleMessage(String url,String tunnelId) throws Exception {
        StandardWebSocketClient client = new StandardWebSocketClient();
        TextWebSocketHandler handler = new TextWebSocketHandler() {
            @Override
            public void handleTextMessage(WebSocketSession session, TextMessage message) {
                // 处理从服务器接收到的消息
                try{
                    log.info("detailTunnelId:{},接收到的事件实时数据：{}" ,tunnelId, message.getPayload());
                    if(StrUtil.isBlank(message.getPayload())){
                        return;
                    }
                    XlwResultData<JSONObject> xlwResultData = JSONObject.parseObject(message.getPayload(), XlwResultData.class);
                    XlwRealTimeEventDTO xlwRealTimeEventDTO = JSONObject.parseObject(xlwResultData.getData().toString(),XlwRealTimeEventDTO.class);
                    EventDetailDO eventDetailDO = XlwRealTimeEventDTO.convert2DO(xlwRealTimeEventDTO);
                    // 补全隧道信息 如果要考虑性能，可以考虑缓存
                    completionTunnelHole(tunnelId,eventDetailDO);
                    eventDetailDO.setThirdEventStatus(xlwRealTimeEventDTO.getEventStatus());
                    EventDetailDO detailDO = eventDetailMapper.selectByThirdPartyId(eventDetailDO.getThirdPartyId());
                    // 判断跟隧道管控事件去重  如果隧道管控同车同类型事件已存在 则标记重复
                    try {
                        Integer milestone = null;
                        if (StringUtils.isNotEmpty(eventDetailDO.getMilestone())){
                            // 信路威与隧道管控的桩号定义不一致。例如：信路威 "K47+517"
                            String eventMileStone = eventDetailDO.getMilestone().replace("K","").replace("ZK","").replace("+","");
                            milestone = Integer.valueOf(eventMileStone);
                            eventDetailDO.setMilestone(eventMileStone);
                        }
                        boolean hasSameEvent = eventDetailService.judgeSameEvent(tunnelId, eventDetailDO.getThirdPartyId(),eventDetailDO.getEventType(),milestone,eventDetailDO.getEventStartTime(), EventSource.XLW.code);
                        if (hasSameEvent){
                            eventDetailDO.setIsRepeat(1);
                        }
                    } catch (NumberFormatException e) {
                        log.error("收到全息事件判断事件重复失败，代码异常。");
                    }
                    if(Objects.isNull(detailDO) ){
                        eventDetailMapper.insert(eventDetailDO);
                        //推送实时事件数据到前端websocket服务
                        eventGateway.pushRealTimeEventData(tunnelId,eventDetailDO.getId());
                    }else{
                        eventDetailDO.setId(detailDO.getId());
                        //如果已存在事件，则只做状态的更新
                        EventDetailDO updateDetailDO = new EventDetailDO();
                        updateDetailDO.setId(detailDO.getId());
                        updateDetailDO.setThirdEventStatus(xlwRealTimeEventDTO.getEventStatus());
                        if(Objects.nonNull(xlwRealTimeEventDTO.getEndTime())){
                            updateDetailDO.setEventEndTime(new Date(xlwRealTimeEventDTO.getEndTime()));
                        }
                        updateDetailDO.setUpdateTime(new Date());
                        eventDetailMapper.updateById(updateDetailDO);
                        log.info("更新事件状态成功,id:{},guid:{},三方状态:{}",detailDO.getId(),eventDetailDO.getThirdPartyId(),xlwRealTimeEventDTO.getEventStatus());
                    }
//                    if(xlwRealTimeEventDTO.getEventStatus() == 0){
                        //当第二次收到信路威结束事件时， 异步获取车流数据和视频回放数据
                        service.submit(()->{
                            historyService.saveEventHistoryData(eventDetailDO);
                        });
//                    }
                }catch (Exception e){
                    log.error("处理实时数据失败",e);
                }
            }

            @Override
            public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
                log.error("WebSocket session closed with error: {}", status.getReason());
                //重连
                connectAndHandleMessage(url,tunnelId);
            }

            @Override
            public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
                log.error("websocket出现错误：",exception);
            }


        };
        WebSocketHttpHeaders webSocketHttpHeaders = new WebSocketHttpHeaders();
        webSocketHttpHeaders.add(XlwConstants.AUTH_HEADER,xlwAuthMapper.getXlwLoginToken());
        client.execute(handler, webSocketHttpHeaders, new URI(url));
        log.info("websocket连接成功,连接地址：{}",url);
    }

    private void completionTunnelHole(String tunnelDetailId,EventDetailDO eventDetailDO){
        eventDetailDO.setTunnelId(tunnelDetailId);
        TunnelDetailDO tunnelDetailDO = tunnelDetailService.getTunnelDetail(tunnelDetailId);
        if(Objects.isNull(tunnelDetailDO)){
            log.error("ws事件数据异常，tunnelDetailId:{}，TunnelDetailDO对象为空",tunnelDetailId);
        }
        eventDetailDO.setDirection(tunnelDetailDO.getDirection());
        eventDetailDO.setDirectionName(tunnelDetailDO.getDirectionName());
        TunnelHoleV2DO tunnelHoleV2DO = tunnelHoleService.getTunnelSfHoleId(tunnelDetailDO.getXlwTunnelId());
        if(Objects.isNull(tunnelHoleV2DO)){
            log.error("ws事件数据异常，xlwTunnelId:{}，tunnelHoleV2DO对象为空",tunnelDetailDO.getXlwTunnelId());
        }
        TunnelBaseDO tunnelBaseDO = tunnelBaseService.getTunnelBase(tunnelHoleV2DO.getTunnelId());
        if(Objects.isNull(tunnelBaseDO)){
            log.error("ws事件数据异常，tunnelId:{}，tunnelBaseDO对象为空",tunnelHoleV2DO.getTunnelId());
        }
        eventDetailDO.setBaseTunnelId(tunnelHoleV2DO.getTunnelId());
        eventDetailDO.setBaseTunnelCode(tunnelBaseDO.getTunnelCode());
        eventDetailDO.setHoleId(tunnelHoleV2DO.getId());
        eventDetailDO.setCreateTime(new Date());

    }

}
