package com.alterdekim.hearthhack.component;

import com.alterdekim.hearthhack.config.ObjectConfig;
import com.alterdekim.hearthhack.config.FS;
import com.alterdekim.hearthhack.config.ServerConfig;
import com.alterdekim.hearthhack.game.GameTag;
import com.alterdekim.hearthhack.parser.CardsXmlParser;
import com.alterdekim.hearthhack.parser.DBFParser;
import com.alterdekim.hearthhack.xml.CardsXML;
import com.alterdekim.hearthhack.xml.XMLEntity;
import com.alterdekim.hearthhack.xml.XMLTag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.util.Map;

@Slf4j
@Component
public class StartupListener {

    @Autowired
    private ObjectConfig dbfConfig;

    @Autowired
    private ServerConfig serverConfig;

    @EventListener
    public void onApplicationEvent(ContextRefreshedEvent event) {
        try {
            dbfConfig.setClientConfig(
                    new String(
                            Files.readAllBytes(
                                    Path.of(
                                            serverConfig.getClientConfigPath()
                                    )
                            )
                    )
            );
            if( serverConfig.getWorkDir() == null ) serverConfig.setWorkDir(new File(".").getCanonicalPath());
            makeDir(FS.xmlDir);
            makeDir(FS.pluginsDir);
            makeDir(FS.dbDir);
            // TODO: make a auto-mkdir using reflection of interface
            if( !Path.of(serverConfig.getWorkDir() + File.separator + FS.dbfDir).toFile().exists() ) initDbf();
            if( !Path.of(serverConfig.getWorkDir() + File.separator + FS.dataDir).toFile().exists() ) initXml();
            dbfConfig.setCards(DBFParser.parseCards(serverConfig.getWorkDir() + File.separator + FS.dbfDir));
            dbfConfig.setCardsXML(DBFParser.parse(serverConfig.getWorkDir() + File.separator + FS.dataDir + File.separator + "enUS.xml", CardsXML.class));
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    private void initDbf() throws Exception {
        makeDir(FS.dbfDir);
        Files.walk(Path.of(serverConfig.getDbfPath()))
                .map(Path::toFile)
                .filter(f -> f.isFile() && f.getName().endsWith("xml"))
                .forEach(f -> {
                    try {
                        Files.copy(f.toPath(), Path.of(serverConfig.getWorkDir() + File.separator + FS.dbfDir + File.separator + f.getName()));
                    } catch (IOException e) {
                        log.error(e.getMessage());
                    }
                });
    }

    private void initXml() throws IOException {
        makeDir(FS.dataDir);
        Map<String, String> m = CardsXmlParser.parse(serverConfig.getCardsXmlPath());
        m.keySet().forEach(k -> {
            try {
                Path p = Path.of(serverConfig.getWorkDir()+File.separator+FS.dataDir+File.separator+k+".xml");
                Files.createFile(p);
                Files.write(p, m.get(k).getBytes(), StandardOpenOption.WRITE);
            } catch (IOException e) {
                log.error(e.getMessage());
            }
        });
    }

    private boolean makeDir(String dirName) {
        return Path.of(serverConfig.getWorkDir() + File.separator + dirName).toFile().mkdirs();
    }

    @Bean
    public DataSource getDataSource() {
        DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
        dataSourceBuilder.driverClassName("org.h2.Driver");
        dataSourceBuilder.url("jdbc:h2:file:"+serverConfig.getWorkDir()+File.separator+FS.dbDir+File.separator+"data.db;DATABASE_TO_UPPER=false;CASE_INSENSITIVE_IDENTIFIERS=TRUE;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;AUTO_RECONNECT=TRUE;MODE=PostgreSQL;");
        dataSourceBuilder.username("SA");
        dataSourceBuilder.password("");
        return dataSourceBuilder.build();
    }
}