package com.njcn.gather.tool.parsepqdif.nativebridge;

import com.sun.jna.NativeLibrary;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Locale;

@Slf4j
public final class PqdifNativeLibraryLoader {

    private static final String RESOURCE_DLL = "/pqdif-native/win-x64/pqdifbasic.dll";
    private static final String DLL_NAME = "pqdifbasic.dll";
    private static final String TEMP_DIR_NAME = "cn-tool-pqdif-native";

    private static volatile boolean prepared;
    private static Path preparedNativeDir;

    private PqdifNativeLibraryLoader() {
    }

    public static synchronized Path ensurePrepared() {
        if (prepared) {
            return preparedNativeDir;
        }

        if (!isWindows()) {
            throw new IllegalStateException("当前接入的是 Windows x64 版 pqdifbasic.dll，非 Windows 环境无法加载");
        }

        try {
            Path nativeDir = Paths.get(System.getProperty("java.io.tmpdir"), TEMP_DIR_NAME, "win-x64");
            Files.createDirectories(nativeDir);

            Path dllPath = nativeDir.resolve(DLL_NAME);
            copyResourceDll(dllPath);

            appendLibraryPath("jna.library.path", nativeDir);
            appendLibraryPath("java.library.path", nativeDir);

            NativeLibrary.addSearchPath("pqdifbasic", nativeDir.toAbsolutePath().toString());
            NativeLibrary.addSearchPath("pqdifbasic.dll", nativeDir.toAbsolutePath().toString());

            log.info("PQDIF native dir = {}", nativeDir.toAbsolutePath());
            log.info("PQDIF native dll = {}", dllPath.toAbsolutePath());

            preparedNativeDir = nativeDir;
            prepared = true;
            return nativeDir;
        } catch (IOException e) {
            throw new IllegalStateException("准备 pqdifbasic.dll 失败：" + e.getMessage(), e);
        }
    }

    private static boolean isWindows() {
        String osName = System.getProperty("os.name", "").toLowerCase(Locale.ROOT);
        return osName.contains("win");
    }

    private static void copyResourceDll(Path dllPath) throws IOException {
        try (InputStream inputStream = PqdifNativeLibraryLoader.class.getResourceAsStream(RESOURCE_DLL)) {
            if (inputStream == null) {
                throw new IOException("classpath 中找不到 " + RESOURCE_DLL);
            }

            Files.copy(inputStream, dllPath, StandardCopyOption.REPLACE_EXISTING);
        }
    }

    private static void appendLibraryPath(String propertyName, Path nativeDir) {
        String nativePath = nativeDir.toAbsolutePath().toString();
        String oldValue = System.getProperty(propertyName);
        String separator = System.getProperty("path.separator");

        if (oldValue == null || oldValue.trim().isEmpty()) {
            System.setProperty(propertyName, nativePath);
            return;
        }

        if (!oldValue.toLowerCase(Locale.ROOT).contains(nativePath.toLowerCase(Locale.ROOT))) {
            System.setProperty(propertyName, nativePath + separator + oldValue);
        }
    }
}
