package me.qwq.doghouse.component;

import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;

import com.zaxxer.hikari.HikariDataSource;

import lombok.extern.slf4j.Slf4j;
import me.qwq.doghouse.config.DoghouseProperties;

/**
 * 重写数据库位置
 */
@Slf4j
@Component
@DependsOn("doghouseProperties")
public class DataSourcePostProcessor implements BeanPostProcessor {

    private static final String RESOURCE_PATH = "blog.db";
    private static final String PREFIX = "jdbc:sqlite:";
    
    @Autowired
    DoghouseProperties doghouseProperties;
    
    /**
     * 配置数据库连接
     * <p>
     * application 指定的 jdbc url 位置存在则使用对应位置，且后续一直以该路径为准（包括调试时修改的数据）。
     * 若不存在则从 classpath 中取初始数据库复制到 jdbc url 指定的位置
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof HikariDataSource hikariDataSource) {
            
            String filePath = hikariDataSource.getJdbcUrl();
            if (filePath == null || !filePath.startsWith(PREFIX)) {
                log.warn(
                    "Unable to obtain a valid SQLite JDBC URL from HikariDataSource; "
                    + "the data source may fail to load.\r\n"
                    + "A valid JDBC URL is typically specified in application.yml "
                    + "or application.properties and should begin with \"jdbc:sqlite:\". "
                    + "Current url: {}", filePath);
                return bean;
            }
            filePath = filePath.substring(PREFIX.length()).trim();
            log.debug("Retrieved HikariDataSource SQLite location: {}", filePath);
            
            if (doghouseProperties.getUseRelativeDbPath()) {
                filePath = Paths.get(doghouseProperties.getWorkPath(), filePath).toString();
                log.debug("Use relative db path with work path: {}, so the db path will be: {}",
                        doghouseProperties.getWorkPath(), filePath);
                hikariDataSource.setJdbcUrl(PREFIX + filePath);
            }
            
            File dest = new File(filePath);
            if (dest.exists()) {
                log.debug("Retrieved HikariDataSource SQLite file exists, will be used as database.");
                return bean;
            }
            
            ClassPathResource original = new ClassPathResource(RESOURCE_PATH);
            if (!original.exists()) {
                log.warn("Cannot find classpath resource: {}", RESOURCE_PATH);
                return bean;
            }
            // 复制到外部 yml 指定路径，已存在则不复制
            File parentDir = dest.getParentFile();
            String destAbsolutePath = dest.getAbsolutePath();
            if (!parentDir.exists() && !parentDir.mkdirs()) {
                // 无法创建放置 SQLite 文件的位置
                log.warn("Failed to create the directory in which the SQLite file should be placed: {}", parentDir.getAbsolutePath());
                return bean;
            }
            
            try (InputStream in = getClass().getClassLoader().getResourceAsStream(RESOURCE_PATH)) {
                if (in == null) {
                    log.warn("Cannot read SQLite resource from classpath: {}", RESOURCE_PATH);
                    return bean;
                }
                Files.copy(in, dest.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
                log.info("SQLite database file has been copy to: {}", destAbsolutePath);
            } catch (Exception e) {
                log.warn("Copt SQLite databse file failed", e);
            }
        }
        return bean;
    }
}
