package com.munjaon.client.server.service;

import com.munjaon.client.server.config.ServerConfig;
import com.munjaon.client.util.LogUtil;
import org.json.simple.JSONObject;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public abstract class Service extends Thread {
    public static final SimpleDateFormat sdf = new SimpleDateFormat("[MM-dd HH:mm:ss]");
    public static final String LOG_DATE_FORMAT = "[MM-dd HH:mm:ss]";

    private String LOG_FILE;
    protected LogUtil logger;
    private Long LAST_PROPERTY_LOAD_TIME = 0L;

    protected boolean IS_SERVER_RUN;          // 서버가 구동중인지 여부
    protected boolean IS_READY_YN;          // 서비스 구동준비가 완료되었는지 체크
    protected boolean IS_RUN_YN;
    protected boolean IS_STOP_YN;

    public Service() {}
    public Service(String serviceName) {
        super(serviceName);
        LOG_FILE = System.getProperty("ROOTPATH") + getProp("LOG_FILE");
    }

    protected String getProp(String name) {
        return getProp(getName(), name);
    }

    public static String getProp(String svc, String name) {
        return PropertyLoader.getProp(svc, name);
    }

    protected void checkRun() {
        this.IS_RUN_YN = getProp("RUN_FLAG") != null && "Y".equals(getProp("RUN_FLAG"));
    }

    protected void checkClientRun() {
        this.IS_SERVER_RUN = getProp("client", "run") != null && "Y".equals(getProp("client", "run"));
    }

    public void reloadCheckRun() {
        if ((System.currentTimeMillis() - this.LAST_PROPERTY_LOAD_TIME) > ServerConfig.INTERVAL_PROPERTY_RELOAD_TIME) {
            checkRun();
            checkClientRun();
            this.LAST_PROPERTY_LOAD_TIME = System.currentTimeMillis();
        }
    }

    public boolean isRun() {
        return IS_SERVER_RUN && IS_RUN_YN && !IS_STOP_YN;
    }

    public boolean isReady() {
        return IS_READY_YN;
    }

    protected void setLogFile(String sLogFile) {
        if ( logger != null ) {
            logger.close();
            logger = null;
        }

        logger = new LogUtil( sLogFile );
    }

    protected void saveSystemLog(Object obj) {
        saveLog(obj, true);
    }

    protected void saveLog(Object obj) {
        saveLog(obj, false);
    }

    protected void saveLog(Object obj, boolean isConsoleOutput) {
        if(isConsoleOutput) {
            System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern(LOG_DATE_FORMAT)) + " {{"+ getName() +"}} "+obj);
        }
        if (logger != null) {
            logger.log(obj);
        } else {
            if (obj instanceof Throwable) {
                LogUtil.log(LOG_FILE, obj);
            } else {
                LogUtil.log(LOG_FILE, "{{"+ getName() +"}} "+obj);
            }
        }
    }

    protected void initLogFile() {
        LOG_FILE = System.getProperty("ROOTPATH") + getProp("LOG_FILE");
        System.out.println("LOG_FILE: " + LOG_FILE);
        setLogFile( LOG_FILE );
        saveSystemLog("Service Log Initializing ... ...");
    }

    @Override
    public void run() {
        while (true) {
            try {
                /* 1. 서비스간의 dependency에 따른 체크 */
                checkReady();
                /* 2. 로그 초기화 */
                initLogFile();
                /* 3. Runflag reload */
                reloadCheckRun();
                saveSystemLog("[SERVICE_READY : " + IS_READY_YN + " || SERVICE_RUN : " + IS_RUN_YN);
                if (isRun() && isReady()) {
                    /* 3. 서비스 초기화 */
                    initResources();
                    /* 4. 서비스 시작 */
                    doService();
                    /* 5. 서비스 자원 해제 */
                    releaseResources();
                    saveSystemLog("[SERVICE IS STOPPED] [... ...]");
                } else {
                    saveSystemLog("[SERVICE IS NOT RUNNING] [... ...]");
                }
                /* 6. 3초간 sleep */
                Thread.sleep(3000);
            } catch (Exception e) {
                saveSystemLog(e);
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException ex) {
                    throw new RuntimeException(ex);
                }
            } finally {
                if(logger != null) { logger.close(); logger = null; }
            }
        }
    }

    /* 서비스간의 dependency에 따른 체크 */
    public abstract void checkReady();
    /* 추가적인 프로퍼티, 서비스 자원 초기화 */
    public abstract void initResources();
    /* 서비스 자원 해제 */
    public abstract void releaseResources();
    /* 서비스 */
    public abstract void doService();
    /* 모니터링을 위한 메소드 */
    public abstract JSONObject monitorService();
}
