package com.jn.sqlhelper.cli;

import ch.qos.logback.classic.util.ContextInitializer;
import com.jn.langx.io.resource.ClassPathResource;
import com.jn.langx.io.resource.FileResource;
import com.jn.langx.io.resource.Resources;
import com.jn.langx.util.Platform;
import com.jn.langx.util.Strings;
import com.jn.langx.util.collection.Collects;
import com.jn.langx.util.collection.Pipeline;
import com.jn.langx.util.function.Consumer;
import com.jn.langx.util.io.IOs;
import com.jn.langx.util.io.file.Files;
import com.jn.langx.util.reflect.Reflects;
import com.jn.sqlhelper.cli.utils.ProjectBanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

@SpringBootApplication
public class CLI {

    private static final String HOME_DIR_KEY = "SQLHelper-CLI.location";
    private static final String RUN_MODE_KEY = "runMode";
    private static Logger logger;

    private static final List<String> configLocations = Collects.emptyArrayList();

    public static void main(String[] args) {
        // run mode
        boolean devMode = Boolean.parseBoolean(System.getProperty("dev", "false"));
        System.clearProperty("dev");
        String runMode = devMode ? "dev" : "production";
        System.setProperty(RUN_MODE_KEY, runMode);

        // homeDir
        String applicationDefaultConfigPath = Reflects.getCodeLocation(CLI.class).getPath();
        String homeDirDefault = "./..";
        if (devMode) {
            homeDirDefault = new File(applicationDefaultConfigPath).getPath();
        }
        String homeDir = System.getProperty(HOME_DIR_KEY, homeDirDefault);
        homeDir = new File(homeDir).getAbsolutePath();
        System.setProperty(HOME_DIR_KEY, homeDir);

        // pid
        recordPid(homeDir);

        Files.makeDirs(homeDir + File.separator + "logs");

        // custom logback.xml
        if (hasCustomLogbackXml(homeDir + File.separator + "config")) {
            System.setProperty(ContextInitializer.CONFIG_FILE_PROPERTY, new File(homeDir + File.separator + "config/logback.xml").getAbsolutePath());
        } else if (hasCustomLogbackXml(homeDir)) {
            System.setProperty(ContextInitializer.CONFIG_FILE_PROPERTY, new File(homeDir + File.separator + "logback.xml").getAbsolutePath());
        }
        logger = LoggerFactory.getLogger(CLI.class);

        // spring.profiles.active, spring.config.location
        String customConfigDir = FileResource.PREFIX + new File(homeDir).getPath() + "/config/";
        String configDirInJar = ClassPathResource.PREFIX + "./";
        configLocations.add(customConfigDir);
        configLocations.add(configDirInJar);

        final List<String> activeProfiles = Collects.emptyArrayList();
        activeProfiles.add("sqlhelper-cli");
        if (devMode) {
            activeProfiles.add("dev");
        }
        String specifiedProfiles = System.getProperty("spring.profiles.active");
        if (specifiedProfiles != null) {
            Pipeline.of(Strings.split(specifiedProfiles, ",")).forEach(new Consumer<String>() {
                @Override
                public void accept(String s) {
                    if (Strings.isNotBlank(s)) {
                        activeProfiles.add(s.trim());
                    }
                }
            });
        }
        System.setProperty("spring.profiles.active", Strings.join(",", activeProfiles));
        System.setProperty("spring.config.location", Strings.join(",", configLocations));

        // startup ...
        final SpringApplication app = new SpringApplication(CLI.class);
        app.setBanner(new ProjectBanner());
        app.setBannerMode(Banner.Mode.LOG);
        final ApplicationContext context = app.run(args);
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                SpringApplication.exit(context);
            }
        });
    }

    private static void recordPid(String homeDir) {
        String pid = Platform.processId;
        File pidFile = new File(homeDir + File.separator + "bin/pid");
        FileWriter fw = null;
        try {
            if (!pidFile.getParentFile().exists()) {
                pidFile.getParentFile().mkdirs();
            }
            if (!pidFile.exists()) {
                pidFile.createNewFile();
            }
            fw = new FileWriter(pidFile, false);
            IOs.write(pid, fw);
        } catch (IOException e) {
            logger.error("failed to write pid: {}", pid);
        } finally {
            IOs.close(fw);
        }
    }

    private static boolean hasCustomLogbackXml(String dir) {
        FileResource fileResource = Resources.loadFileResource(dir + File.separator + "logback.xml");
        return fileResource.exists();
    }


}