package com.its.web.service.traffic;

import com.its.web.dto.message.ResultDto;
import com.its.web.dto.traffic.*;
import com.its.web.mapper.its.traffic.TrafficMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.sql.Blob;
import java.sql.SQLException;
import java.util.*;

@Slf4j
@RequiredArgsConstructor
@Service
public class TrafficService {

    private final TrafficMapper mapper;

    /**
     * CCTV 조회
     * @return
     */
    public List<TbCctvCtlrDto> findAllCctv() {
        return this.mapper.findAllCctv();
    }

    /**
     * 홈페이지 CCTV 조회
     * @return
     */
    public List<TbCctvCtlrDto> findCctvList() {
        return this.mapper.findCctvList();
    }

    /**
     * VMS 조회
     * @return
     */
    public List<TbVmsCtlrDto> findAllVms() {
        List<TbVmsCtlrDto> resultList = mapper.findAllVms();
        resultList.forEach((TbVmsCtlrDto obj)->{
            Long vmsCtlrNmbr = obj.getVmsCtlrNmbr();
            List<VmsDsplPhaseDto> list = this.mapper.findVmsDsplPhaseInfo(vmsCtlrNmbr.toString());
            if (list != null) {
                obj.setMsg(new ArrayList<VmsDsplPhaseDto>());
                list.forEach((VmsDsplPhaseDto dto) -> {
                    obj.getMsg().add(dto);
                });
            }
        });
        return resultList;
    }

    /**
     * VMS 표출 이미지 조회
     * @return 이미지 byteArray
     */
    public byte [] findVmsDsplImage(String vmsCtlrNmbr, String phase) {
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("vmsCtlrNmbr", vmsCtlrNmbr);
        paramMap.put("phase", phase);

        Map<String, Object> resultMap = this.mapper.findVmsDsplImage(paramMap);

        if (resultMap != null && resultMap.get("VMS_DSPL_MSG_IMAG") != null) {
            Blob blob = (Blob) resultMap.get("VMS_DSPL_MSG_IMAG");
            try {
                if ((int)blob.length() > 0) {
                    return blob.getBytes(1, (int) blob.length());
                }
            }
            catch (SQLException e) {
                log.error("Please Check the Sql Exception :{}",  e.getStackTrace());
            }
        }
        return null;
    }

    /**
     * 돌발상황 조회
     * @return
     */
    public List<TbIncdOcrrDto> findAllIncident() {
        return this.mapper.findAllIncident();
    }

    /**
     * 지도 소통정보 버텍스 조회
     * @param req 버텍스 그리는 범위
     * @return
     */
    public List<VertexDto> findVertexByRange(VertexDto.VertexDtoReq req) {
        Map<String, Object> paramMap = new HashMap<>();
        List<VertexDto> resultList = new ArrayList<>();
        if (req != null) {
            if ( req.getLevl()  != null &&
                 req.getNeLat() != null &&
                 req.getNeLng() != null &&
                 req.getSwLat() != null &&
                 req.getSwLng() != null   ) {
                int level = req.getLevl();
                paramMap.put("neLat", req.getNeLat());
                paramMap.put("neLng", req.getNeLng());
                paramMap.put("swLat", req.getSwLat());
                paramMap.put("swLng", req.getSwLng());
                if (level <= 2) {
                    paramMap.put("levl",  level);
                    resultList = this.mapper.findLinkVertexByRange(paramMap);
                }
                else if (level < 6) {
                    if (level == 3) {
                        level = 4;
                    }
                    paramMap.put("levl",  level);
                    resultList = this.mapper.findIfscVertexByRange(paramMap);
                }
                else if (level >= 6) {
                    if (level == 7) {
                        level = 6;
                    }
                    else if (level >= 8){
                        level = 7;
                    }
                    paramMap.put("levl",  level);
                    resultList = this.mapper.findRoadVertexByRange(paramMap);
                }
            }
            else {
                log.error("파라미터 정보를 확인 해주세요. {}", req);
            }
        }
        else {
            log.error("조회할 파라미터 정보가 없습니다.");
        }
        return resultList;
    }

    public Map<String, List<TbAtrdDto>> findAllAtrd() {
        List<TbAtrdDto> atrdList = this.mapper.findAllAtrd();
        Map<String, List<TbAtrdDto>> resultMap = new HashMap<>();
        atrdList.forEach(atrd->{
            if (atrd != null) {
                if (resultMap.get(atrd.getAtrdNm()) == null) {
                    resultMap.put(atrd.getAtrdNm(), new ArrayList<TbAtrdDto>());
                }
                resultMap.get(atrd.getAtrdNm()).add(atrd);
            }
        });
        return resultMap;
    }

    public List<TbAtrdDto> findAtrdNameList() {
        return this.mapper.findAtrdNameList();
    }

    public List<TbAtrdDto> findAtrdVertexByIdAndLevel(TbAtrdDto.TbAtrdDtoReq req) {
        List<TbAtrdDto> atrdList = new ArrayList<>();
        Map<String, Object> paramMap = new HashMap<>();
        if (req != null &&
            req.getLevl() != null &&
            req.getUpHill() != null &&
            req.getDownHill() != null
        ) {
            paramMap.put("levl", req.getLevl());
            paramMap.put("upHillId", req.getUpHill());
            paramMap.put("downHillId", req.getDownHill());

            int level = req.getLevl();
            if (level > 5) {
                if (level == 7) {
                    level = 6;
                }
                else if (level >= 8){
                    level = 7;
                }
                paramMap.put("levl",  level);
                atrdList = this.mapper.findAtrdRoadVertexByIdAndLevel(paramMap);
            }
            else if (level > 3) {
                atrdList = this.mapper.findAtrdIfscVertexByIdAndLevel(paramMap);
            }
            else {
                atrdList = this.mapper.findAtrdLinkVertexByIdAndLevel(paramMap);
            }
        }
        else {
            log.error("파라미터 정보를 확인해주세요.");
        }
        return atrdList;
    }

    public List<TbAtrdInfoDto> findAllAtrdInfo() {
        List<TbAtrdInfoDto> result = new ArrayList<>();
        String[] levelArr = {"1", "2", "3", "4", "5", "6", "7"};

        for (String level : levelArr) {
            TbAtrdInfoDto dto = new TbAtrdInfoDto();
            dto.setLevel(level);
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("levl", level);
            if (level.equals("1") || level.equals("2")) {
                dto.setType("link");
                dto.setList(this.mapper.findAtrdLinkVertexByIdAndLevel(paramMap));
            }
            else if (level.equals("3") || level.equals("4") || level.equals("5")) {
                dto.setType("ifsc");
                dto.setList(this.mapper.findAtrdIfscVertexByIdAndLevel(paramMap));
            }
            else {
                dto.setType("road");
                dto.setList(this.mapper.findAtrdRoadVertexByIdAndLevel(paramMap));
            }
            result.add(dto);
        }
        return result;
    }

    public List<TbIncdOcrrDto> findMainIncident() {
        List<TbIncdOcrrDto> result = this.mapper.findMainIncident();
        for (TbIncdOcrrDto dto: result) {
            String agoStr = "-";
            String incdTitl = dto.getIncdTitl();

            if (null == incdTitl || "".equals(incdTitl)) {
                dto.setIncdTitl("-");
            }

            try {// 숫자가 나와야 정상이지만 혹시라도 아닐경우를 대비해야한다.
                //화면에 보여줄때 돌발 시간이 1시간 보다 커질 경우 대비하여 분, 시간, 일 전으로 분류
                int agoMinutes= Integer.parseInt(dto.getAgoMinutes());
                if (agoMinutes < 60) { // 분 단위
                    agoStr = agoMinutes + "분 전";
                }
                else if (agoMinutes < 1440) { //시간 단위
                    agoStr = (agoMinutes / 60) + "시간 전";
                }
                else { // 일 단위
                    agoStr = (agoMinutes / 1440) + "일 전";
                }

            }
            catch (NumberFormatException e) {
                log.error("Can not parsed ago minutes... {}", dto.getAgoMinutes());
            }
            dto.setAgoMinutes(agoStr);
        }
        return result;
    }

    public ResultDto updateCctvHmpgUseYn(Map<String, String> paramMap) {
        ResultDto result = new ResultDto();
        int affectedRow = this.mapper.updateCctvHmpgUseYn(paramMap);
        String message = "설정하신 홈페이지 표출정보를 수정하였습니다.";
        String success = "S";
        if (affectedRow <= 0) {
            message = "설정하신 홈페이지 표출정보가 수정되지 않았습니다.";
            success = "F";
        }

        result.setMessage(message);
        result.setSuccess(success);
        return result;
    }
}
