package cn.axzo.workflow.server.initializer;

import cn.hutool.json.JSONUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.spring.SpringProcessEngineConfiguration;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static org.flowable.common.engine.impl.AbstractEngineConfiguration.DB_SCHEMA_UPDATE_DROP_CREATE;
import static org.flowable.common.engine.impl.AbstractEngineConfiguration.DB_SCHEMA_UPDATE_FALSE;

/**
 * Ext Database Initializer
 *
 * @author wangli
 * @since 2023/11/18 18:00
 */
@Component
@Slf4j
@AllArgsConstructor
public class ExtDatabaseInitializer implements ApplicationRunner {
    private static final String FILE_PREFIX = "ext_ax_";
    private final JdbcTemplate jdbcTemplate;
    private final ResourceLoader resourceLoader;
    private final ApplicationContext applicationContext;
    private ResourcePatternResolver resourcePatternResolver;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        SpringProcessEngineConfiguration springProcessEngineConfiguration =
                (SpringProcessEngineConfiguration) applicationContext.getBean("springProcessEngineConfiguration");
        if (Objects.equals(DB_SCHEMA_UPDATE_FALSE, springProcessEngineConfiguration.getDatabaseSchemaUpdate())) {
            return;
        }

        List<String> tables = selectExtTables();
        if (Objects.equals(DB_SCHEMA_UPDATE_DROP_CREATE, springProcessEngineConfiguration.getDatabaseSchemaUpdate())) {
            tables.forEach(this::executeSqlScript);
        }
        log.info("tables: {}", JSONUtil.toJsonStr(tables));
        localSqlFiles().forEach(i -> {
            if (!tables.contains(i.replace(".sql", "").toUpperCase())) {
                log.info("execute sql script: {}", i);
                executeSqlScript(i);
            }
        });

    }

    private List<String> localSqlFiles() throws IOException {
        return Arrays.stream(resourcePatternResolver.getResources("classpath:sql/" + FILE_PREFIX + "*.sql"))
                .map(Resource::getFilename).collect(Collectors.toList());
    }

    private List<String> selectExtTables() {
        String query = "SHOW TABLES LIKE 'EXT_AX_%'";
        return jdbcTemplate.queryForList(query, String.class).stream().filter(StringUtils::hasLength)
                .map(String::toUpperCase).collect(Collectors.toList());
    }

    private void executeSqlScript(String fileName) {
        Resource resource = resourceLoader.getResource("classpath:sql/" + fileName.toLowerCase());

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()))) {
            StringBuilder scriptBuilder = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                scriptBuilder.append(line);
            }

            // Split SQL statements and execute each one
            String[] sqlStatements = scriptBuilder.toString().split(";");
            for (String sql : sqlStatements) {
                jdbcTemplate.execute(sql);
            }
        } catch (IOException e) {
            // Handle IOException
            e.printStackTrace();
        }
    }

}
