package com.eactive.eai.common.logger.async;

import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.server.EAIServerManager;
import com.eactive.eai.common.util.LogKeys;
//import com.eactive.eai.data.entity.onl.logger.HttpAdapterExtraHeader;
import com.eactive.eai.data.entity.onl.logger.HttpAdapterExtraLog;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.io.FilenameUtils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.Set;
import java.util.Stack;

public class HttpAdapterExtraLogH2Factory {
    private SessionFactory sessionFactory ;
    private HikariDataSource dataSource;

    private static HttpAdapterExtraLogH2Factory httpAdapterExtraLogH2Factory = new HttpAdapterExtraLogH2Factory();

    private HttpAdapterExtraLogH2Factory(){
        sessionFactory = buildSessionFactory();
    }

    public static HttpAdapterExtraLogH2Factory getInstance(){
        return httpAdapterExtraLogH2Factory;
    }

    private SessionFactory buildSessionFactory() {
        try {
            Configuration configuration = new Configuration();
            configuration.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
            configuration.setProperty("hibernate.hbm2ddl.auto", "update");
            configuration.setProperty("hibernate.show_sql", "true");
            configuration.setProperty("hibernate.format_sql", "true");
            configuration.setProperty("hibernate.use_sql_comments", "true");
            configuration.setProperty("hibernate.auto_quote_keyword", "true");
            configuration.setProperty("hibernate.globally_quoted_identifiers", "true");

            String logBaseDirectory = PropManager.getInstance().getProperty(LogKeys.LOGGER_INFO, LogKeys.LOG_DIRECOTRY_PREFIX);
            String localServer = EAIServerManager.getInstance().getLocalServerName();
            String serverLogPath = FilenameUtils.concat(logBaseDirectory, localServer);
            makeDirs(serverLogPath);
            String httpLogDbFilePath = FilenameUtils.concat(serverLogPath, "http_log");
            httpLogDbFilePath = httpLogDbFilePath.replace("\\", "/");
            // HikariCP 설정
            HikariConfig hikariConfig = new HikariConfig();
            hikariConfig.setDriverClassName("org.h2.Driver");
            hikariConfig.setJdbcUrl("jdbc:h2:file:"+httpLogDbFilePath);
            hikariConfig.setUsername("sa");
            hikariConfig.setPassword("");
            hikariConfig.setMaximumPoolSize(20);
            hikariConfig.setMinimumIdle(5);
            hikariConfig.setIdleTimeout(300000);
            hikariConfig.setMaxLifetime(600000);

            dataSource = new HikariDataSource(hikariConfig);
            configuration.getProperties().put("hibernate.connection.datasource", dataSource);

            // 엔티티 클래스 추가
            configuration.addAnnotatedClass(HttpAdapterExtraLog.class);
//            configuration.addAnnotatedClass(HttpAdapterExtraHeader.class);

            return configuration.buildSessionFactory();
        } catch (Throwable ex) {
            ex.printStackTrace();
            throw new ExceptionInInitializerError(ex);
        }
    }

    public synchronized Session openSession(){
        if(sessionFactory == null || sessionFactory.isClosed()){
            sessionFactory = buildSessionFactory();
        }
        return sessionFactory.openSession();
    }

    public void closeSessionFactory() {
        if (sessionFactory != null && !sessionFactory.isClosed()) {
            sessionFactory.close();
            sessionFactory = null;
        }
        if (dataSource != null && dataSource instanceof HikariDataSource) {
            dataSource.close();
        }
    }

    private static void makeDirs(String path) throws Exception{
        File directory = new File(path);

        if (directory.exists()){
            return;
        }

        Stack<File> stack = new Stack<File>();
        //check
        File p = directory;
        stack.push(p);
        while (true){
            p = p.getParentFile();
            if (p.exists()){
                break;
            }else{
                stack.push(p);
            }
        }
        while(!stack.empty()){
            File s = stack.pop();
            s.mkdir();
            //그룹까지 rwx로 권한이 필요한 경우가 많음 필요 시 수정 할 것
            Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwxrwxr-x");
            Files.setPosixFilePermissions(s.toPath(), perms);
        }
    }
}
