package com.its.op.service.its.cctv;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.its.op.config.CctvServerConfig;
import com.its.op.dao.repository.its.cctv.TbCctvCtlrRepository;
import com.its.op.dao.repository.its.cctv.TbCctvCtrlHsRepository;
import com.its.op.dto.its.cctv.*;
import com.its.op.entity.its.cctv.TbCctvCtlr;
import com.its.utils.SysUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.NoSuchElementException;
import java.util.Optional;

@Slf4j
@RequiredArgsConstructor
@Service
public class CctvControlService {

    private final TbCctvCtlrRepository repo;
    private final TbCctvCtrlHsRepository hsRepo;
    private final CctvControlZenoService zenoControl;
    private final CctvControlProbeService probeControl;
    private final CctvServerConfig cctvServerConfig;

    // 데이터 1건 조회, 없으면 exception
    private TbCctvCtlr requireOne(Long id) throws NoSuchElementException {
        Optional<TbCctvCtlr> info = this.repo.findById(id);
        if (info.isPresent()) {
            return info.get();
        }
        else {
            throw new NoSuchElementException("데이터가 존재하지 않습니다: " + id);
        }
//        return repo.findById(id)
//                .orElseThrow(() -> new NoSuchElementException("데이터가 존재하지 않습니다: " + id));
    }

    /**
     * PROBE Digital Preset control
     * @param ipAddr
     * @param userId
     * @param userPswd
     * @param req
     * @return
     */
    public CctvControlDto.CctvControlRes controlPresetProbe(String ipAddr, String userId, String userPswd, CctvControlDto.CctvControlPresetReq req) {
        CctvControlDto.CctvControlRes result = new CctvControlDto.CctvControlRes(req.getCommand(), req.getAction(), 0, "success");
        String controlUri = this.probeControl.getPresetCmd(req.getAction(), req.getNo());
        byte[] controlData = this.probeControl.getPresetControlCmd(req.getAction(), req.getNo());
        if (controlUri == null) {
            result.setResult(9, "unknown command");
            return result;
        }
        return requestHttpPostProbe(result, controlUri, controlData, ipAddr, userId, userPswd);
    }

    /**
     * PROBE Digital PTZ control
     * @param ipAddr
     * @param userId
     * @param userPswd
     * @param req
     * @return
     */
    public CctvControlDto.CctvControlRes controlPtzProbe(String ipAddr, String userId, String userPswd, CctvControlDto.CctvControlPtzReq req) {
        CctvControlDto.CctvControlRes result = new CctvControlDto.CctvControlRes(req.getCommand(), req.getAction(), 0, "success");
        String controlUri = this.probeControl.getPtzCmd(req.getCommand(), req.getAction(), req.getSpeed());
        byte[] controlData = this.probeControl.getPtzControlCmd(req.getCommand(), req.getAction(), req.getSpeed());
        if (controlUri == null) {
            result.setResult(9, "unknown command");
            return result;
        }
        return requestHttpPostProbe(result, controlUri, controlData, ipAddr, userId, userPswd);
    }
    public CctvControlDto.CctvControlRes requestHttpPostProbe(CctvControlDto.CctvControlRes result, String controlUri, byte[] controlData, String ipAddr, String userId, String userPswd) {
        String encoding = Base64.getEncoder().encodeToString((userId + ":" + userPswd).getBytes());
        String apiUrl = "http://" + ipAddr + controlUri;
        log.info("{}, Basis: {}", apiUrl, encoding);

        HttpURLConnection connection = null;
        try {
            URL url = new URL(apiUrl);
            connection = (HttpURLConnection)url.openConnection();
            connection.setConnectTimeout(5000); //서버에 연결되는 Timeout 시간 설정
            connection.setReadTimeout(5000); // InputStream 읽어 오는 Timeout 시간 설정

            connection.setDoOutput(true); //POST 데이터를 OutputStream 으로 넘겨 주겠다는 설정
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/octet-stream");
            connection.setRequestProperty("Accept", "text/html, */*");
            connection.setRequestProperty("Accept-Encoding", "identity");
            connection.setRequestProperty("Authorization", "Basic " + encoding);
            //connection.setRequestProperty("charset", "UTF-8");
            //connection.setRequestProperty("Content-Length", Integer.toString(controlData.length));
            connection.setRequestProperty("User-Agent", "Mozilla/3.0");

            //connection.setUseCaches(false);
            //connection.setDefaultUseCaches(false);

            DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
            wr.write(controlData);
            wr.flush();
            wr.close();

            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                String line;
                StringBuilder sb = new StringBuilder();
                try (
                    BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));
                ) {
                    while ((line = br.readLine()) != null) {
                        sb.append(line).append("\n");
                    }
                    //br.close();
                    log.info("HTTP_OK: CCTV, {}, {}", ipAddr, sb);
                    result.setResult(0, sb.toString());
                }
                catch (IOException e) {
                    log.error("requestHttpPostProbe: IOException");
                    result.setResult(4, "CCTV 제어기에 연결 할 수 없습니다. 통신 확인 후 작업을 진행해 주세요.");
                }
            } else {
                log.error("HTTP_FAIL: {}", connection.getResponseMessage());
                if (connection.getResponseMessage() == null) {
                    result.setResult(2, "cctv network fail.");
                } else {
                    result.setResult(3, connection.getResponseMessage());
                }
            }
        } catch (IOException e){
            log.error("Exception: IOException");
            result.setResult(5, "CCTV 제어기에 연결 할 수 없습니다. 통신 확인 후 작업을 진행해 주세요.");
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
        return result;
    }
    public CctvControlDto.CctvControlRes requestHttpPostProbe2(CctvControlDto.CctvControlRes result, String controlUri, String controlData, String ipAddr, String userId, String userPswd) {
        String encoding = Base64.getEncoder().encodeToString((userId + ":" + userPswd).getBytes());
        String apiUrl = "http://" + ipAddr + controlUri;
        log.info("{}, Basis: {}", apiUrl, encoding);

        HttpURLConnection connection = null;
        try {
            URL url = new URL(apiUrl);
            connection = (HttpURLConnection)url.openConnection();
            connection.setConnectTimeout(5000); //서버에 연결되는 Timeout 시간 설정
            connection.setReadTimeout(5000); // InputStream 읽어 오는 Timeout 시간 설정

            connection.setDoOutput(true); //POST 데이터를 OutputStream 으로 넘겨 주겠다는 설정
            connection.setDoInput(true);
//   Accept: */*
//   Accept-Encoding: gzip, deflate
//   Accept-Language: ko
//   Authorization: Basic YWRtaW46MTIzNDU=
//   Cache-Control: no-cache
//   Connection: Keep-Alive
//   Content-Length: 8
//   Content-Type: text/html; charset=UTF-8
//   Cookie: nLANGUAGE=0; nDevType=4; nChnCount=1; nRtspPort=554; nRtmpPort=1935; nMsgPort=8080; nUserLevel=4; szUsername=admin; szPassword=12345
//   Host: 172.16.53.45
//   Referer: http://172.16.53.45/login.asp
//   User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko

            connection.setRequestMethod("POST");
            connection.setRequestProperty("Accept", "*/*");
            connection.setRequestProperty("Accept-Encoding", "gzip, deflate");
            connection.setRequestProperty("Accept-Language", "ko");
            connection.setRequestProperty("Authorization", "Basic " + encoding);
            //connection.setRequestProperty("charset", "UTF-8");
            //connection.setRequestProperty("Content-Length", Integer.toString(controlData.length));
            connection.setRequestProperty("Content-Type", "text/html; charset=UTF-8");
            connection.setRequestProperty("User-Agent", "Mozilla/3.0");

            //connection.setUseCaches(false);
            //connection.setDefaultUseCaches(false);

            DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
            wr.write(controlData.getBytes());
            wr.flush();
            wr.close();

            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                String line;
                StringBuilder sb = new StringBuilder();
                try (
                        BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));
                ) {
                    while ((line = br.readLine()) != null) {
                        sb.append(line).append("\n");
                    }
                    //br.close();
                    log.info("HTTP_OK: CCTV, {}, {}", ipAddr, sb);
                    result.setResult(0, sb.toString());
                }
                catch (IOException e) {
                    log.error("requestHttpPostProbe: IOException");
                    result.setResult(4, "CCTV 제어기에 연결 할 수 없습니다. 통신 확인 후 작업을 진행해 주세요.");
                }
            } else {
                log.error("HTTP_FAIL: {}", connection.getResponseMessage());
                if (connection.getResponseMessage() == null) {
                    result.setResult(2, "cctv network fail.");
                } else {
                    result.setResult(3, connection.getResponseMessage());
                }
            }
        } catch (IOException e){
            log.error("Exception: IOException");
            result.setResult(5, "CCTV 제어기에 연결 할 수 없습니다. 통신 확인 후 작업을 진행해 주세요.");
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
        return result;
    }

    /**
     * ZENO Preset control
     * @param ipAddr
     * @param userId
     * @param userPswd
     * @param req
     * @return
     */
    public CctvControlDto.CctvControlRes controlPresetZeno(String ipAddr, String userId, String userPswd, CctvControlDto.CctvControlPresetReq req) {
        CctvControlDto.CctvControlRes result = new CctvControlDto.CctvControlRes(req.getCommand(), req.getAction(), 0, "success");
        byte[] controlData = this.zenoControl.getPresetCmd(req.getAction(), req.getNo(), req.getSpeed(), req.getTime(), req.getName());
        if (controlData == null) {
            result.setResult(9, "unknown command");
            return result;
        }
        return requestHttpPostZeno(result, controlData, ipAddr, userId, userPswd);
    }

    /**
     * ZENO PTZ control
     * @param ipAddr
     * @param userId
     * @param userPswd
     * @param req
     * @return
     */
    public CctvControlDto.CctvControlRes controlPtzZeno(String ipAddr, String userId, String userPswd, CctvControlDto.CctvControlPtzReq req) {
        CctvControlDto.CctvControlRes result = new CctvControlDto.CctvControlRes(req.getCommand(), req.getAction(), 0, "success");
        byte[] controlData = this.zenoControl.getPtzCmd(req.getCommand(), req.getAction(), req.getSpeed());
        if (controlData == null) {
            result.setResult(9, "unknown command");
            return result;
        }
        return requestHttpPostZeno(result, controlData, ipAddr, userId, userPswd);
    }

    /**
     * ZENO Request HTTP Post
     * @param result
     * @param controlData
     * @param ipAddr
     * @param userId
     * @param userPswd
     * @return
     */
    public CctvControlDto.CctvControlRes requestHttpPostZeno(CctvControlDto.CctvControlRes result, byte[] controlData, String ipAddr, String userId, String userPswd) {
        String encoding = Base64.getEncoder().encodeToString((userId + ":" + userPswd).getBytes());
        String apiUrl = "http://" + ipAddr + "/cgi-bin/admin/uartctrl.cgi";
        log.info("{}, Basis: {}, {}", apiUrl, encoding, SysUtils.byteArrayToHex(controlData));

        HttpURLConnection connection = null;
        try {
            // POST /cgi-bin/admin/uartctrl.cgi HTTP/1.1
            // User-Agent: Mozilla/3.0 (compatible; Indy Library)
            // Accept: text/html, */*
            // Indy 로 할경우
            // [POST /cgi-bin/admin/uartctrl.cgi HTTP/1.1
            // User-Agent: Java/1.8.0_25
            // Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
            URL url = new URL(apiUrl);
            connection = (HttpURLConnection)url.openConnection();
            connection.setConnectTimeout(5000); //서버에 연결되는 Timeout 시간 설정
            connection.setReadTimeout(5000); // InputStream 읽어 오는 Timeout 시간 설정

            connection.setDoOutput(true); //POST 데이터를 OutputStream 으로 넘겨 주겠다는 설정
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/octet-stream");
            connection.setRequestProperty("Accept", "text/html, */*");
            connection.setRequestProperty("Accept-Encoding", "identity");
            connection.setRequestProperty("Authorization", "Basic " + encoding);
            //connection.setRequestProperty("charset", "UTF-8");
            //connection.setRequestProperty("Content-Length", Integer.toString(controlData.length));
            connection.setRequestProperty("User-Agent", "Mozilla/3.0");

            //connection.setUseCaches(false);
            //connection.setDefaultUseCaches(false);

            DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
            wr.write(controlData);
            wr.flush();
            wr.close();

            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                String line;
                StringBuilder sb = new StringBuilder();
                try (
                        BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));
                ) {
                    while ((line = br.readLine()) != null) {
                        sb.append(line).append("\n");
                    }
                    //br.close();
                    log.info("HTTP_OK: CCTV, {}, {}", ipAddr, sb);
                    result.setResult(0, sb.toString());
                }
                catch (IOException e) {
                    log.error("requestHttpPostZeno: IOException");
                    result.setResult(4, "CCTV 제어기에 연결 할 수 없습니다. 통신 확인 후 작업을 진행해 주세요.");
                }
            } else {
                log.error("HTTP_FAIL: {}", connection.getResponseMessage());
                if (connection.getResponseMessage() == null) {
                    result.setResult(2, "cctv network fail.");
                } else {
                    result.setResult(3, connection.getResponseMessage());
                }
            }
        } catch (IOException e){
            log.error("Exception: IOException");
            result.setResult(5, "CCTV 제어기에 연결 할 수 없습니다. 통신 확인 후 작업을 진행해 주세요.");
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
        return result;
    }

    /**
     * CCTV PTZ 컨트롤
     * @param id
     * @param req
     * @return
     */
//    public CctvControlDto.CctvControlRes controlPtz(Long id, CctvControlDto.CctvControlPtzReq req) {
//        log.info("{}", req);
//        TbCctvCtlr cctv = this.requireOne(id);
//        if (StringUtils.equals("1", cctv.getCctvTypeCd())) {
//            // 제노 CCTV
//            return this.controlPtzZeno(cctv.getCctvCtlrIp(), "root", "pass", req);
//        }
//        else if (StringUtils.equals("2", cctv.getCctvTypeCd())) {
//            // 프로브디지털
//            return this.controlPtzProbe(cctv.getCctvCtlrIp(), "admin", "12345", req);
//        }
//        return new CctvControlDto.CctvControlRes(req.getCommand(), req.getAction(), 1, "unknown cctv type");
//    }

    /**
     * CCTV Preset 컨트롤
     * @param id
     * @param req
     * @return
     */
//    public CctvControlDto.CctvControlRes controlPreset(Long id, CctvControlDto.CctvControlPresetReq req) {
//        log.info("{}", req);
//        TbCctvCtlr cctv = this.requireOne(id);
//        if (StringUtils.equals("1", cctv.getCctvTypeCd())) {
//            // 제노 CCTV
//            return this.controlPresetZeno(cctv.getCctvCtlrIp(), "root", "pass", req);
//        }
//        else if (StringUtils.equals("2", cctv.getCctvTypeCd())) {
//            // 프로브디지털
//            return this.controlPresetProbe(cctv.getCctvCtlrIp(), "admin", "12345", req);
//        }
//        return new CctvControlDto.CctvControlRes(req.getCommand(), req.getAction(), 1, "unknown cctv type");
//    }

    /**
     * Http Get Request
     * @param apiUri
     * @return
     */
    public String get(String apiUri) {
        String ipAddr = this.cctvServerConfig.getIpAddress();
        int port = this.cctvServerConfig.getPort();
        String apiUrl = String.format("http://%s:%d%s", ipAddr, port, apiUri);
        //JSONObject responseJson = null;
        String result = null;
        HttpURLConnection conn = null;
        try {
            URL url = new URL(apiUrl);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000); //서버에 연결되는 Timeout 시간 설정
            conn.setReadTimeout(5000); // InputStream 읽어 오는 Timeout 시간 설정
            //TODO con.addRequestProperty("x-api-key", RestTestCommon.API_KEY); //key 값 설정

            conn.setRequestMethod("GET");

            // URLConnection 에 대한 doOutput 필드값을 지정된 값으로 설정한다.
            // URL 연결은 입출력에 사용될 수 있다.
            // URL 연결을 출력용으로 사용하려는 경우 DoOutput 플래그를 true 로 설정하고, 그렇지 않은 경우는 false 로 설정해야 한다. 기본값은 false 이다.
            conn.setDoOutput(false);

            StringBuilder sb = new StringBuilder();
            if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                //Stream 을 처리해줘야 하는 귀찮음이 있음.
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
                String line;
                while ((line = br.readLine()) != null) {
                    sb.append(line).append("\n");
                }
                br.close();
                result = sb.toString();
                //responseJson = new JSONObject(sb.toString());
            }
            else {
                log.error("get: {}: {}", apiUrl, conn.getResponseMessage());
            }
        }
        catch (IOException e) {
            log.error("get: IOException error: {}", apiUrl);
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
        return result;
    }

    public CctvParamControlDto.CctvParamValueRes requestParam(Long id) {
        log.info("requestParam: {}", id);
        String apiUri = String.format("/api/cctv/control/param-qry/%d", id);
        CctvParamControlDto.CctvParamValueRes result = new CctvParamControlDto.CctvParamValueRes(10, "CCTV 파라미터 요청 중 오류가 발생했습니다.");
        String resultString = get(apiUri);
        if (resultString != null) {
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                log.info("requestParam: {}", resultString);
                result = objectMapper.readValue(resultString, CctvParamControlDto.CctvParamValueRes.class);
            } catch (JsonProcessingException e) {
                log.error("requestParam: result json parsing error: {}", resultString);
                return new CctvParamControlDto.CctvParamValueRes(9, "CCTV 파라미터 요청 결과 수신 중 오류가 발생했습니다.");
            }
        }
        return result;
    }

    public CctvStatusDto.CctvStatusDtoRes requestStatus(Long id) {
        log.info("requestStatus: {}", id);
        String apiUri = String.format("/api/cctv/control/status/%d", id);
        CctvStatusDto.CctvStatusDtoRes result = new CctvStatusDto.CctvStatusDtoRes(10, "CCTV 상태정보 요청 중 오류가 발생했습니다.", null);
        String resultString = get(apiUri);
        if (resultString != null) {
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                log.info("requestStatus: {}", resultString);
                result = objectMapper.readValue(resultString, CctvStatusDto.CctvStatusDtoRes.class);
            } catch (JsonProcessingException e) {
                log.error("requestStatus: result json parsing error: {}", resultString);
                return new CctvStatusDto.CctvStatusDtoRes(9, "CCTV 상태정보 요청 결과 수신 중 오류가 발생했습니다.", null);
            }
        }
        return result;
    }

    public CctvPresetControlDto.CctvPresetValueRes requestPresetValue(Long id) {
        log.info("requestPresetValue: {}", id);
        String apiUri = String.format("/api/cctv/control/preset-value/%d", id);
        CctvPresetControlDto.CctvPresetValueRes result = new CctvPresetControlDto.CctvPresetValueRes(10, "CCTV 카메라 현재위치 요청 중 오류가 발생했습니다.");
        String resultString = get(apiUri);
        if (resultString != null) {
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                log.info("requestPresetValue: {}", resultString);
                result = objectMapper.readValue(resultString, CctvPresetControlDto.CctvPresetValueRes.class);
            } catch (JsonProcessingException e) {
                log.error("requestPresetValue: result json parsing error: {}", resultString);
                return new CctvPresetControlDto.CctvPresetValueRes(9, "CCTV 카메라 현재위치 요청 결과 수신 중 오류가 발생했습니다.");
            }
        }
        return result;
    }

    /**
     * Http Post Request
     * @param apiUri
     * @param params
     * @return
     */
    public String post(String apiUri, String params) {
        String ipAddr = this.cctvServerConfig.getIpAddress();
        int port = this.cctvServerConfig.getPort();
        String apiUrl = String.format("http://%s:%d%s", ipAddr, port, apiUri);

        log.info("post: {}, {}", apiUrl, params);
        HttpURLConnection conn = null;
        String result = null;
        try {
            URL url = new URL(apiUrl);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000); //서버에 연결되는 Timeout 시간 설정
            conn.setReadTimeout(5000); // InputStream 읽어 오는 Timeout 시간 설정

            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json;utf-8");
            conn.setRequestProperty("Accept", "application/json");
            //conn.setRequestProperty("Connection", "keep-alive");
            conn.setDoOutput(true);


            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()));
            // JSON 형식의 데이터 셋팅
//            JSONObject commands = new JSONObject();
//            JSONArray jsonArray = new JSONArray();

            // JSON 형식의 데이터 셋팅 끝

            // 데이터를 STRING 으로 변경
//            Gson gson = new GsonBuilder().setPrettyPrinting().create();
//            String jsonOutput = gson.toJson(params);

            //bw.write(params.toString());
            bw.write(params);
            bw.flush();
            bw.close();

            // 보내고 결과값 받기
            int responseCode = conn.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                StringBuilder sb = new StringBuilder();
                String line = "";
                while ((line = br.readLine()) != null) {
                    sb.append(line);
                }
                result = sb.toString();
            }
            else {
                log.error("post: {}: {}", apiUrl, conn.getResponseMessage());
            }
        }
        catch (IOException e) {
            log.error("post: IOException error: {}", apiUrl);
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }

        return result;
    }

    public CctvParamControlDto.CctvParamControlRes controlParam(Long id, CctvParamControlDto.CctvParamControlReq req) {
        log.info("controlParam: {}, {}", id, req);
        String apiUri = String.format("/api/cctv/control/param-set/%d", id);
        CctvParamControlDto.CctvParamControlRes result = new CctvParamControlDto.CctvParamControlRes(10, "CCTV 파라미터 설정 요청 중 오류가 발생했습니다.");
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            String params = objectMapper.writeValueAsString(req);
            String resultString = post(apiUri, params);
            if (resultString != null) {
                try {
                    log.info("controlParam: {}", resultString);
                    result = objectMapper.readValue(resultString, CctvParamControlDto.CctvParamControlRes.class);
                } catch (JsonProcessingException e) {
                    log.error("controlParam: result json parsing error: {}", resultString);
                    return new CctvParamControlDto.CctvParamControlRes(9, "CCTV 파라미터 설정 요청 결과 수신 중 오류가 발생했습니다.");
                }
            }
        } catch (JsonProcessingException e) {
            return new CctvParamControlDto.CctvParamControlRes(11, "CCTV 파라미터 설정 요청 메시지 생성에 실패하였습니다[설정값 확인].");
        }

        String CTRL_TYPE = "4"; // 파라미터 설정
        String CTRL_VAL = req.getFanOffTmpr() + ", " + req.getFanOffTmpr() + ", " + req.getHetrOnTmpr() + ", " + req.getHetrOffTmpr();
        Integer CTRL_RESULT = result.getError() % 100;
        String USER_ID = req.getUserId();
        this.hsRepo.insertHs(SysUtils.getSysTime(), id, CTRL_TYPE, CTRL_VAL, CTRL_RESULT, USER_ID);

        return result;
    }

    public CctvPtzControlDto.CctvPtzControlRes controlPtz(Long id, CctvPtzControlDto.CctvControlPtzReq req) {
        log.info("controlPtz: {}, {}", id, req);
        String apiUri = String.format("/api/cctv/control/ptz/%d", id);
        CctvPtzControlDto.CctvPtzControlRes result = new CctvPtzControlDto.CctvPtzControlRes(req.getCommand(), req.getAction(), 10, "CCTV PTZ 제어 요청 중 오류가 발생했습니다.");
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            String params = objectMapper.writeValueAsString(req);
            String resultString = post(apiUri, params);
            if (resultString != null) {
                try {
                    log.info("controlPtz: {}", resultString);
                    result = objectMapper.readValue(resultString, CctvPtzControlDto.CctvPtzControlRes.class);
                } catch (JsonProcessingException e) {
                    log.error("controlPtz: result json parsing error: {}", resultString);
                    return new CctvPtzControlDto.CctvPtzControlRes(req.getCommand(), req.getAction(), 9, "CCTV PTZ 제어 요청 결과 수신 중 오류가 발생했습니다.");
                }
            }
        } catch (JsonProcessingException e) {
            return new CctvPtzControlDto.CctvPtzControlRes(req.getCommand(), req.getAction(), 11, "CCTV CCTV PTZ 제어 요청 메시지 생성에 실패하였습니다[설정값 확인].");
        }
        return result;
    }

    public CctvPresetControlDto.CctvPresetControlRes controlPreset(Long id, CctvPresetControlDto.CctvPresetControlReq req) {
        log.info("controlPreset: {}, {}", id, req);
        String apiUri = String.format("/api/cctv/control/preset/%d", id);
        CctvPresetControlDto.CctvPresetControlRes result = new CctvPresetControlDto.CctvPresetControlRes(10, "CCTV 프리셋 제어 요청 중 오류가 발생했습니다.");
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            String params = objectMapper.writeValueAsString(req);
            String resultString = post(apiUri, params);
            if (resultString != null) {
                try {
                    log.info("controlPreset: {}", resultString);
                    result = objectMapper.readValue(resultString, CctvPresetControlDto.CctvPresetControlRes.class);
                } catch (JsonProcessingException e) {
                    log.error("controlPreset: result json parsing error: {}", resultString);
                    return new CctvPresetControlDto.CctvPresetControlRes(9, "CCTV 프리셋 제어 요청 결과 수신 중 오류가 발생했습니다.");
                }
            }
        } catch (JsonProcessingException e) {
            return new CctvPresetControlDto.CctvPresetControlRes(11, "CCTV 프리셋 제어 요청 메시지 생성에 실패하였습니다[설정값 확인].");
        }

        String CTRL_TYPE = "5"; // 프리셋제어
        String CTRL_VAL = req.getPan() + ", " + req.getTilt() + ", " + req.getZoom() + ", " + req.getFocus();
        Integer CTRL_RESULT = result.getError() % 100;
        String USER_ID = req.getUserId();
        this.hsRepo.insertHs(SysUtils.getSysTime(), id, CTRL_TYPE, CTRL_VAL, CTRL_RESULT, USER_ID);

        return result;
    }

    public CctvVarCharControlDto.CctvVarCharControlRes controlVarCharSet(Long id, CctvVarCharControlDto.CctvVarCharControlSetReq req) {
        log.info("controlVarCharSet: {}, {}", id, req);
        String apiUri = String.format("/api/cctv/control/var-char-set/%d", id);
        CctvVarCharControlDto.CctvVarCharControlRes result = new CctvVarCharControlDto.CctvVarCharControlRes(10, "CCTV 가변문자설정 요청 중 오류가 발생했습니다.");
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            String params = objectMapper.writeValueAsString(req);
            String resultString = post(apiUri, params);
            if (resultString != null) {
                try {
                    log.info("controlVarCharSet: {}", resultString);
                    result = objectMapper.readValue(resultString, CctvVarCharControlDto.CctvVarCharControlRes.class);
                } catch (JsonProcessingException e) {
                    log.error("controlVarCharSet: result json parsing error: {}", resultString);
                    return new CctvVarCharControlDto.CctvVarCharControlRes(9, "CCTV 가변문자설정 요청 결과 수신 중 오류가 발생했습니다.");
                }
            }
        } catch (JsonProcessingException e) {
            return new CctvVarCharControlDto.CctvVarCharControlRes(11, "CCTV 가변문자설정 요청 메시지 생성에 실패하였습니다[설정값 확인].");
        }

        String CTRL_TYPE = "3"; // 가변문자설정
        String CTRL_VAL = String.valueOf(req.getSectorNo()) + ", " + req.getCh1Char() + ", " + req.getCh2Char();
        Integer CTRL_RESULT = result.getError() % 100;
        String USER_ID = req.getUserId();
        this.hsRepo.insertHs(SysUtils.getSysTime(), id, CTRL_TYPE, CTRL_VAL, CTRL_RESULT, USER_ID);

        return result;
    }

    public CctvVarCharControlDto.CctvVarCharControlRes controlVarCharDel(Long id, CctvVarCharControlDto.CctvVarCharControlDelReq req) {
        log.info("controlVarCharDel: {}, {}", id, req);
        String apiUri = String.format("/api/cctv/control/var-char-del/%d", id);
        CctvVarCharControlDto.CctvVarCharControlRes result = new CctvVarCharControlDto.CctvVarCharControlRes(10, "CCTV 가변문자삭제 요청 중 오류가 발생했습니다.");
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            String params = objectMapper.writeValueAsString(req);
            String resultString = post(apiUri, params);
            if (resultString != null) {
                try {
                    log.info("controlVarCharDel: {}", resultString);
                    result = objectMapper.readValue(resultString, CctvVarCharControlDto.CctvVarCharControlRes.class);
                } catch (JsonProcessingException e) {
                    log.error("controlVarCharDel: result json parsing error: {}", resultString);
                    return new CctvVarCharControlDto.CctvVarCharControlRes(9, "CCTV 가변문자삭제 요청 결과 수신 중 오류가 발생했습니다.");
                }
            }
        } catch (JsonProcessingException e) {
            return new CctvVarCharControlDto.CctvVarCharControlRes(11, "CCTV 가변문자삭제 요청 메시지 생성에 실패하였습니다[설정값 확인].");
        }

        String CTRL_TYPE = "2"; // 가변문자삭제
        String CTRL_VAL = String.valueOf(req.getSectorNo());
        Integer CTRL_RESULT = result.getError() % 100;
        String USER_ID = req.getUserId();
        this.hsRepo.insertHs(SysUtils.getSysTime(), id, CTRL_TYPE, CTRL_VAL, CTRL_RESULT, USER_ID);

        return result;
    }

    public CctvControlDto.CctvControlResetRes controlReset(Long id, CctvControlDto.CctvControlResetReq req) {
        log.info("controlReset: {}, {}", id, req);
        String apiUri = String.format("/api/cctv/control/reset/%d", id);
        CctvControlDto.CctvControlResetRes result = new CctvControlDto.CctvControlResetRes(10, "CCTV 가변문자삭제 요청 중 오류가 발생했습니다.");
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            String params = objectMapper.writeValueAsString(req);
            String resultString = post(apiUri, params);
            if (resultString != null) {
                try {
                    log.info("controlReset: {}", resultString);
                    result = objectMapper.readValue(resultString, CctvControlDto.CctvControlResetRes.class);
                } catch (JsonProcessingException e) {
                    log.error("controlReset: result json parsing error: {}", resultString);
                    return new CctvControlDto.CctvControlResetRes(9, "CCTV RESET 요청 결과 수신 중 오류가 발생했습니다.");
                }
            }
        } catch (JsonProcessingException e) {
            return new CctvControlDto.CctvControlResetRes(11, "CCTV RESET 요청 메시지 생성에 실패하였습니다[설정값 확인].");
        }

        String CTRL_TYPE = "0"; // SW 리셋
        String CTRL_VAL = String.valueOf(req.getResetType());
        Integer CTRL_RESULT = result.getError() % 100;
        String USER_ID = req.getUserId();
        if (1 == req.getResetType()) {
            CTRL_TYPE = "1";    // HW 리셋
        }
        this.hsRepo.insertHs(SysUtils.getSysTime(), id, CTRL_TYPE, CTRL_VAL, CTRL_RESULT, USER_ID);

        return result;
    }
}
