package com.its.wthr.openApi.vilageFcstInfoService;

import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 기상청 단기예보 조회서비스 Base Class
 */
@Slf4j
public class VilageFcstInfo {

    private String baseDate;
    private String baseTime;

    public VilageFcstInfo() {
        setQueryDateTime();
    }

    public void setQueryDateTime() {
        this.baseDate = getCurrentDay();
        this.baseTime = changeQueryTime(getCurrentHour());
    }

    /**
     * 현재 일자를 구한다(YYYYMMDD)
     * @return
     */
    public String getCurrentDay() {
        LocalDateTime dateTime = LocalDateTime.now();
        DateTimeFormatter fmtDay = DateTimeFormatter.ofPattern("yyyyMMdd");
        return dateTime.format(fmtDay);
    }

    /**
     * 현재의 시간을 구한다.(HH24)
     * @return
     */
    public int getCurrentHour() {
        LocalDateTime dateTime = LocalDateTime.now();
        DateTimeFormatter fmtHour = DateTimeFormatter.ofPattern("HH");
        return Integer.parseInt(dateTime.format(fmtHour));
    }

    /**
     * 주어진 시간을 기준으로 조회시각을 구한다.
     * 주어진 시간에 따라 데이터 시간 설정(3시간 마다 업데이트 됨, 0200, 0500, 0800, 1100, 1400, 1700, 2000, 2300 (1일 8회))
     * @param hour
     * @return
     */
    public String changeQueryTime(int hour) {
        String queryTime = "";
        switch(hour) {
            case  2: case  3: case  4: queryTime = "0200"; break;
            case  5: case  6: case  7: queryTime = "0500"; break;
            case  8: case  9: case 10: queryTime = "0800"; break;
            case 11: case 12: case 13: queryTime = "1100"; break;
            case 14: case 15: case 16: queryTime = "1400"; break;
            case 17: case 18: case 19: queryTime = "1700"; break;
            case 20: case 21: case 22: queryTime = "2000"; break;
            default:                   queryTime = "2300"; break;
        }
        return queryTime;
    }

    /**
     * 요청의 응답코드에 대한 오류메시지를 구한다.
     * @param error
     * @return
     */
    public String getErrorMessage(int error) {
        String errorMessage;
        switch(error) {
            case  0: errorMessage = error + ": NORMAL_SERVICE, 정상"; break;
            case  1: errorMessage = error + ": APPLICATION_ERROR, 어플리케이션 에러"; break;
            case  2: errorMessage = error + ": DB_ERROR, 데이터베이스 에러"; break;
            case  3: errorMessage = error + ": NODATA_ERROR, 데이터없음 에러"; break;
            case  4: errorMessage = error + ": HTTP_ERROR, HTTP 에러"; break;
            case  5: errorMessage = error + ": SERVICETIME_OUT, 서비스 연결실패 에러"; break;
            case 10: errorMessage = error + ": INVALID_REQUEST_PARAMETER_ERROR, 잘못된 요청 파라메터 에러"; break;
            case 11: errorMessage = error + ": NO_MANDATORY_REQUEST_PARAMETERS_ERROR, 필수요청 파라메터가 없음"; break;
            case 12: errorMessage = error + ": NO_OPENAPI_SERVICE_ERROR, 해당 오픈 API 서비스가 없거나 폐기됨"; break;
            case 20: errorMessage = error + ": SERVICE_ACCESS_DENIED_ERROR, 서비스 접근거부"; break;
            case 21: errorMessage = error + ": TEMPORARILY_DISABLE_THE_SERVICEKEY_ERROR, 일시적으로 사용할 수 없는 서비스 키"; break;
            case 22: errorMessage = error + ": LIMITED_NUMBER_OF_SERVICE_REQUESTS_EXCEEDS_ERROR, 서비스 요청제한횟수 초과에러"; break;
            case 30: errorMessage = error + ": SERVICE_KEY_IS_NOT_REGISTERED_ERROR, 등록되지 않은 서비스키"; break;
            case 31: errorMessage = error + ": DEADLINE_HAS_EXPIRED_ERROR, 기한만료된 서비스키"; break;
            case 32: errorMessage = error + ": UNREGISTERED_IP_ERROR, 등록되지 않은 IP"; break;
            case 33: errorMessage = error + ": UNSIGNED_CALL_ERROR, 서명되지 않은 호출"; break;
            case 99: errorMessage = error + ": UNKNOWN_ERROR, 기타에러"; break;
            default: errorMessage = error + ": 알수없는 오류코드"; break;
        }
        return errorMessage;
    }

    /**
     * 하늘상태(SKY) 코드 설명
     * @param value
     * @return
     */
    public String getSkyDesc2(String value) {
        if (value == null) {
            return "-";
        }
        if ("1".equals(value.trim())) {
            return "맑음";
        }
        if ("3".equals(value.trim())) {
            return "구름 많음";  // Mostly Cloudy
        }
        if ("4".equals(value.trim())) {
            return "흐림";      // Cloudy
        }
        // 비, ㄲ먀ㅜ
        return "-";
    }
    /**
     * 하늘상태(SKY) 코드 설명
     * @param value
     * @return
     */
    public String getSkyDesc(String value) {
        if (value == null || "-".equals(value.trim())) {
            return "-";
        }
        int code = -99;
        try {
            code = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            return value;
        }

        if (code >= 0 && code <= 5) {
            return "맑음";
        }
        if (code >= 6 && code <= 8) {
            return "구름많음";
        }
        if (code >= 9 && code <= 10) {
            return "흐림";
        }
        return value;
    }

    /**
     * 강수형태(PTY) 코드 설명
     * @param pty
     * @return
     */
    public String etPtyDesc(String pty) {
        if (pty == null) {
            return "-";
        }
        if ("0".equals(pty.trim())) {
            return "없음";    // 초단기, 단기
        }
        if ("1".equals(pty.trim())) {
            return "비";     // 초단기, 단기
        }
        if ("2".equals(pty.trim())) {
            return "비/눈";   // 초단기, 단기
        }
        if ("3".equals(pty.trim())) {
            return "눈";     // 초단기, 단기
        }
        if ("4".equals(pty.trim())) {
            return "소나기";   // 단기
        }
        if ("5".equals(pty.trim())) {
            return "빗방울";   // 초단기
        }
        if ("6".equals(pty.trim())) {
            return "빗방울눈날림";    // 초단기
        }
        if ("7".equals(pty.trim())) {
            return "눈날림";   // 초단기
        }
        return "-";
    }

    /**
     * 강수량(RN1, PCP) 범주 및 표시방법
     * @param value
     * @return
     */
    public String getRn1PcpDesc(String value) {
        if (value == null || "-".equals(value.trim()) || "0".equals(value.trim())) {
            return "강수없음";
        }

        float f = Float.parseFloat(value);
        if(f < 1.0f) return "1.0mm 미만 ";
        else if(f >= 1.0f && f < 30.0f) return "1.0~29.0mm";
        else if(f >= 30.0f && f < 50.0f) return "30.0~50.0mm";
        else return "50.0mm 이상";
    }

    /**
     * 신적설(SNO) 범주 표시방법
     * @param value
     * @return
     */
    public String getSnoDesc(String value) {
        if (value == null || "-".equals(value.trim()) || "0".equals(value.trim())) {
            return "적설없음";
        }

        float f = Float.parseFloat(value);
        if(f < 1.0f) return "1.0cm 미만 ";
        else if(f >= 1.0f && f < 5.0f) return value+"cm";
        else return "5.0cm 이상";
    }

    public String lookUpApi(StringBuilder urlBuilder) {
        String result = "";
        try {
            URL url = new URL(urlBuilder.toString());
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(10000);   //The timeout in mills
            conn.setRequestMethod("GET");
            conn.setRequestProperty("Content-type", "application/json");
            log.info("Response code: {}.", conn.getResponseCode());

            BufferedReader rd;
            if (conn.getResponseCode() >= 200 && conn.getResponseCode() <= 300) {
                rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            } else {
                rd = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
            }

            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = rd.readLine()) != null) {
                sb.append(line);
            }
            rd.close();
            conn.disconnect();
            result = sb.toString();
        } catch (MalformedURLException e) {
            log.error("MalformedURLException Error: {}", e.getMessage());
        } catch (IOException e) {
            log.error("IOException Error: {}", e.getMessage());
        }
        return result;
    }

}
