package com.tsi.sig.server.service;

import com.tsi.sig.server.app.AppUtils;
import com.tsi.sig.server.dto.EvpsData;
import com.tsi.sig.server.mapper.MainMapper;
import com.tsi.sig.server.repository.ApplicationRepository;
import com.tsi.sig.server.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;


@Service
@Slf4j
public class MainService {

    private final MainMapper mainMapper;
    private final ApplicationRepository repo = (ApplicationRepository) AppUtils.getBean(ApplicationRepository.class);


    public MainService(MainMapper mainMapper) {
        this.mainMapper = mainMapper;
    }

    public List<CvibNodeVO> getCvibNodeInfo(HashMap<String, Object> paramMap) {
        return this.mainMapper.getCvibNodeInfo(paramMap);
    }

    public List<CvibNodeVO> getCvibMapNodeList(HashMap<String, Object> paramMap) {
        return this.mainMapper.getCvibMapNodeList(paramMap);
    }

    public List<CvibNodeVO> getLodeList() {
        return this.mainMapper.getNodeList();
    }

//    public List<CvibNodeStatusVo> getCvibNodeStatusList(Map<String, String> paramMap) {
    public Map<String, List<?>> getCvibNodeStatusList(Map<String, String> paramMap) throws ParseException {
//        log.info("paramMap : {}",paramMap);
        long start = System.currentTimeMillis();

        Map<String, CvibNodeStatusVo> repoMap = repo.getNodeStatusMap();

        List<CvibStatusVo> statusList = repo.getStatusList();
        Map<String, List<?>> resultMap = new HashMap<>();
        List<CvibNodeStatusVo> resultList = new ArrayList<>();

        List<CvibNodeVO> regionList = this.getRegionList(paramMap);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date now = new Date();
        if (regionList.size() > 0) {
            for (CvibNodeVO vo : regionList) {
                String nodeId = vo.getNodeid();
                if (repoMap.get(nodeId) != null) {
                    CvibNodeStatusVo statusVo = repoMap.get(nodeId);
                    if (statusVo.commStatus) {
                        Date connDate = null;
                        Date date = null;
                        if (statusVo.getConnDate() != null) {
                            connDate = format.parse(statusVo.getConnDate());
                        }

                        if (statusVo.getLocalDate() != null) {
                            date = format.parse(statusVo.getLocalDate());
                        }

                        if (repoMap.get(nodeId).getTurns().size() == 0) {
                            repoMap.get(nodeId).setCommStatus(false);
                        }
                        if (now.getTime() - connDate.getTime() > 10000) {
                            statusVo.setCommStatus(false);
                            statusVo.setTurns(new ArrayList<>());
                        }
//                        if ( date     != null &&
//                             connDate != null &&
//                             connDate.getTime() - date.getTime() <= 10000) {
                            resultList.add(repoMap.get(nodeId));
//                        }
                    }
                    else {
                        statusVo.setTurns(new ArrayList<>());
                    }
                }
            }
        }

//        Map<String, CvibNodeStatusVo> resultMap = repo.getNodeStatusMap();
//
//        List<CvibNodeStatusVo> resultList = null;
//        if (resultMap != null && resultMap.size() > 0) {
//            resultList = new ArrayList<>(resultMap.values());
//        }
//        long end = System.currentTimeMillis();
        //log.info("================ 소요시간: {} ms", (end - start));
        //List<CvibNodeStatusVo> resultList = new ArrayList<>();

//        for (String nodeId : nodeIdList) {
//
//        }
        resultMap.put("sectionList", resultList);
        resultMap.put("statusList", statusList);

//        return resultList;
        return resultMap;
    }

    public CvibNodeStatusVo getCvibNodeDetail(String nodeId) {
        ApplicationRepository repo = (ApplicationRepository) AppUtils.getBean(ApplicationRepository.class);
        Map<String, CvibNodeStatusVo> resultMap = repo.getNodeStatusMap();
        CvibNodeStatusVo resultVo = null;
        if (resultMap != null && resultMap.size() > 0) {
            resultVo = resultMap.get(nodeId);
            try {
                if (resultVo != null) {
                    Date conDate = repo.getStringParseToDate(resultVo.getConnDate());
                    Date date = repo.getStringParseToDate(resultVo.getLocalDate());
                    if (conDate.getTime() - date.getTime() > 10000) {
                        //resultVo.setCommStatus(false);
                        //resultVo.setTurns(new ArrayList<>());
                    }
                }
            }
            catch (ParseException ex) {
                log.error("날짜 형식의 문자열이 아닙니다. conn_date 또는 date 값을 확인 해주세요.");
            }
        }
        return resultVo;
    }

    public List<CvibNodeVO> getRegionList(Map<String, String> paramMap) {
        List<CvibNodeVO> list = new ArrayList<>();
        if (paramMap != null && paramMap.size() == 4) {
            double minX = Double.parseDouble(paramMap.get("minX"));
            double minY = Double.parseDouble(paramMap.get("minY"));
            double maxX = Double.parseDouble(paramMap.get("maxX"));
            double maxY = Double.parseDouble(paramMap.get("maxY"));
            ApplicationRepository repo = (ApplicationRepository) AppUtils.getBean(ApplicationRepository.class);
            List<CvibNodeVO> allList;
            if (repo.getNodeList() != null && repo.getNodeList().size() > 0) {
               allList = repo.getNodeList();
            }
            else {
                allList = mainMapper.getNodeList();
            }

            for (CvibNodeVO vo : allList) {
                if (minY <= vo.getLat() &&
                        maxY >= vo.getLat() &&
                        minX <= vo.getLng() &&
                        maxX >= vo.getLng()
                ) {
                    list.add(vo);
                }
            }
        }
        return list;
    }

    public ResultVo refreshNodeList() {
        ResultVo result = new ResultVo();
        try {
            ApplicationRepository repo = (ApplicationRepository) AppUtils.getBean(ApplicationRepository.class);
            List<CvibNodeVO> list = this.mainMapper.getNodeList();
            if (repo.getNodeList() != null && repo.getNodeList().size() > 0) {
                repo.getNodeList().clear();
            }

            for (CvibNodeVO vo : list) {
                repo.getNodeList().add(vo);
            }

            if (repo.getNodeList().size() == list.size()) {
                result.setSuccess(true);
                result.setErrorMsg("");
            }
            else {
                result.setSuccess(false);
                result.setErrorMsg("노드 정보 새로고침 중 오류가 발생하였습니다.");
            }
        }
        catch (DataAccessException ex) {
            result.setSuccess(false);
            result.setErrorMsg("refreshNodeList - Cause DataAccessException");
        }
        return result;
    }

//    public List<EvpServiceVo> getEvpServiceList() {
//        List<EvpServiceVo> result = this.mainMapper.getEvpServiceList();
//        if (result.size() > 0) {
//            for (EvpServiceVo vo : result) {
//                Map<String, Object> paramMap = new HashMap<>();
//                paramMap.put("serviceId", vo.getServiceId());
//                vo.setRouteList(this.mainMapper.getEvpRouteList(paramMap));
//                vo.setNodeList(this.mainMapper.getEvpNodeList(paramMap));
//                vo.setPhaseList(this.mainMapper.getEvpSignalCurrList(paramMap));
//                vo.setEventList(this.mainMapper.getEvpEventCurrList(paramMap));
//            }
//        }
//        return result;
//    }

    public List<EvpServiceVo> getEvpServiceList() {
        Map<String, EvpsData> evpDataMap = repo.getEvpDataMap();
        List<EvpServiceVo> result = new ArrayList<>();
        if (!evpDataMap.isEmpty()) {
            Map<String, String> regionMap = new HashMap<>();
            List<EvpRegionVo> regions = this.mainMapper.getEvpRegion();
            for (EvpRegionVo vo : regions) {
                regionMap.put(vo.getRegionId(), vo.getRegionName());
            }
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            LocalDateTime now = LocalDateTime.now();

            Iterator<Map.Entry<String, EvpsData>> it = evpDataMap.entrySet().iterator();
            while(it.hasNext()) {
                Map.Entry<String, EvpsData> entry = it.next();
                EvpsData data = entry.getValue();
                EvpServiceVo vo = data.getEvpServiceVo();
                if (vo == null) {
                    it.remove();
                    continue;
                }

                // clctDt null/empty 체크
                String clctDt = vo.getClctDt();
                if (clctDt == null || clctDt.isEmpty()) {
                    it.remove();
                    continue;
                }

                // 날짜 파싱 오류 대비
                LocalDateTime targetTime;
                try {
                    targetTime = LocalDateTime.parse(clctDt, formatter);
                    // 시간 차이 계산
                    long minutesDiff = ChronoUnit.MINUTES.between(targetTime, now);
                    if (minutesDiff >= 10) {
                        it.remove();
                        continue;
                    }
                } catch (Exception e) {
                    it.remove();
                    continue;
                }

                result.add(vo);
                // ServiceId 체크
                String sid = vo.getServiceId();
                if (sid == null || sid.length() < 3) {
                    continue;
                }
                String regionKey = sid.substring(0, 3);
                vo.setRegionName(regionMap.get(regionKey));
            }
        }
        return result;

//        List<EvpsData> list = new ArrayList<>(evpDataMap.values());
//        List<String> keys = new ArrayList<>(evpDataMap.keySet());
//        Map<String, String> regionMap = new HashMap<>();
//
//        if (list.size() > 0) {
//            List<EvpRegionVo> regions = this.mainMapper.getEvpRegion();
//
//            for (EvpRegionVo vo : regions) {
//                regionMap.put(vo.getRegionId(), vo.getRegionName());
//            }
//
//
//            int idx = 0;
//            for (EvpsData data : list) {
//                EvpServiceVo vo = data.getEvpServiceVo();
//                String clctDt = vo.getClctDt();
//                if (clctDt == null || clctDt.equals("")) {
//                    repo.getEvpDataMap().remove(keys.get(idx));
//                    continue;
//                }
//                String sid = vo.getServiceId();
//
//                if (sid != null && sid.length() > 3) {
//                    String serviceId = sid.substring(0, 3);
//                    if (regionMap.size() > 0 && regionMap.get(serviceId) != null) {
//                        vo.setRegionName(regionMap.get(serviceId));
//                    }
//                }
//
//
//                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//                LocalDateTime targetTime = LocalDateTime.parse(clctDt, formatter);
//                LocalDateTime now = LocalDateTime.now();
//                long minutesDiff = ChronoUnit.MINUTES.between(targetTime, now);
//                if (minutesDiff >= 10) {
//                    repo.getEvpDataMap().remove(keys.get(idx));
//                }
//                else {
//                    result.add(vo);
//                }
//                idx++;
//            }
//        }
//
//        return result;
    }

    public List<EvpRouteVo> getEvpRouteList(Map<String, Object> paramMap) {
        return this.mainMapper.getEvpRouteList(paramMap);
    }

    public List<EvpSignalVo> getEvpSignalList(Map<String, Object> paramMap) {
        return this.mainMapper.getEvpSignalList(paramMap);
    }

    public List<EvpServiceVo> getEvpHistoryList(Map<String, Object> paramMap) {
        List<EvpServiceVo> result = this.mainMapper.getEvpHistoryList(paramMap);
        if (result != null && result.size() > 0) {
            for (EvpServiceVo vo : result) {
                Map<String, Object> param = new HashMap<>();
                param.put("serviceId", vo.getServiceId());
                vo.setRouteList(new ArrayList<>());
                vo.setNodeList(new ArrayList<>());
                vo.setPhaseList(new ArrayList<>());
                vo.setEventList(new ArrayList<>());
            }
        }
        return result;
    }
    public EvpServiceVo getEvpHistoryDetail(Map<String, Object> paramMap) {
        EvpServiceVo result = new EvpServiceVo();
        result.setServiceId((String) paramMap.get("serviceId"));
        result.setRouteList(this.mainMapper.getEvpRouteList(paramMap));
        result.setNodeList(this.mainMapper.getEvpNodeList(paramMap));
        result.setPhaseList(this.mainMapper.getEvpSignalList(paramMap));
        result.setEventList(this.mainMapper.getEvpEventList(paramMap));
        return result;
    }

    public List<EvpCenterVo> getCenterCode() {
        return this.mainMapper.getEvpCenterCode();
    }

    public List<NodeStatisticsVo> getNodeStatistics(Map<String, Object> paramMap) {
        return this.mainMapper.getNodeStatusStat(paramMap);
    }
    public List<NodeStatisticsVo> getNodeStatusCntStat(Map<String, Object> paramMap) {
        return this.mainMapper.getNodeStatusCntStat(paramMap);
    }

    public List<RegionVo> getRegionCd() {
        return this.mainMapper.getRegionCd();
    }
}
