package com.axis.innovators.box.plugins;

import com.axis.innovators.box.AxisInnovatorsBox;
import com.axis.innovators.box.tools.FolderCreator;
import com.axis.innovators.box.util.PythonResult;
import com.axis.innovators.box.util.RunPython;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author tzdwindows 7
 */
public class PluginPyLoader {
    public static final String PLUGIN_PATH = FolderCreator.getPyPluginFolder();
    private static final Logger LOGGER = LogManager.getLogger(PluginPyLoader.class);
    private static final Map<String, PyPluginDescriptor> loadedPlugins = new HashMap<>();
    private static final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors();

    /**
     * Python插件描述类
     */
    public static class PyPluginDescriptor {
        private final String id;
        private final String name;
        private final Path scriptPath;
        private final Path pluginRoot;
        private boolean enabled;
        private PythonResult lastResult;

        public PyPluginDescriptor(String id, String name, Path pluginRoot) {
            this.id = id;
            this.name = name;
            this.pluginRoot = pluginRoot;
            this.scriptPath = pluginRoot.resolve("main.py");
            this.enabled = false;
        }

        // Getters
        public String getId() { return id; }
        public String getName() { return name; }
        public Path getScriptPath() { return scriptPath; }
        public boolean isEnabled() { return enabled; }
        public PythonResult getLastResult() { return lastResult; }
    }

    /**
     * 加载所有Python插件
     */
    public static void loadAllPlugins() {
        if (PLUGIN_PATH == null || PLUGIN_PATH.isEmpty()) {
            LOGGER.warn("Python plugin path not configured");
            return;
        }

        try (Stream<Path> pathStream = Files.walk(Path.of(PLUGIN_PATH), 3)) {
            List<Path> pluginPaths = pathStream
                    .filter(path -> path.endsWith("main.py"))
                    .collect(Collectors.toList());

            ExecutorService executor = Executors.newFixedThreadPool(CORE_POOL_SIZE);
            CountDownLatch latch = new CountDownLatch(pluginPaths.size());
            AtomicInteger progressCounter = new AtomicInteger(0);
            int total = pluginPaths.size();

            for (Path path : pluginPaths) {
                executor.submit(() -> {
                    try {
                        loadPlugin(path);
                        int currentProgress = progressCounter.incrementAndGet();
                        updateProgress(currentProgress, total);
                    } finally {
                        latch.countDown();
                    }
                });
            }

            latch.await(5, TimeUnit.MINUTES);
            executor.shutdownNow();
        } catch (IOException | InterruptedException e) {
            LOGGER.error("Plugin loading interrupted", e);
            Thread.currentThread().interrupt();
        }
    }

    private static void updateProgress(int current, int total) {
        AxisInnovatorsBox.getMain().progressBarManager.updateSubProgress(
                "Loading Python Plugins",
                current,
                total
        );
    }

    /**
     * 加载单个Python插件
     */
    private static void loadPlugin(Path scriptPath) {
        try {
            Path pluginRoot = scriptPath.getParent();

            PyPluginDescriptor descriptor = readPluginMetadata(pluginRoot);

            List<String> dependencies = new ArrayList<>();
            dependencies.add(pluginRoot.toString());
            Path libsPath = pluginRoot.resolve("libs");
            if (Files.exists(libsPath)) {
                dependencies.add(libsPath.toString());
            }

            PythonResult result = RunPython.executeWithJython(
                    scriptPath.toString(),
                    dependencies
            );

            descriptor.lastResult = result;
            descriptor.enabled = result.getExitCode() == 0;

            loadedPlugins.put(descriptor.id, descriptor);
            LOGGER.info("Loaded Python plugin: {} - {}", descriptor.id, descriptor.name);

        } catch (Exception e) {
            LOGGER.error("Failed to load plugin at {}", scriptPath, e);
        }
    }

    /**
     * 读取插件元数据（从metadata.json）
     */
    private static PyPluginDescriptor readPluginMetadata(Path pluginRoot) throws IOException {
        String pluginId = pluginRoot.getFileName().toString();
        String pluginName = pluginId;
        Gson gson = new Gson();
        Path metaFile = pluginRoot.resolve("metadata.json");
        if (Files.exists(metaFile)) {
            try (Reader reader = Files.newBufferedReader(metaFile)) {
                PluginMetadata meta = gson.fromJson(reader, PluginMetadata.class);
                if (meta.getId() != null && !meta.getId().isEmpty()) {
                    pluginId = meta.getId();
                }
                if (meta.getName() != null && !meta.getName().isEmpty()) {
                    pluginName = meta.getName();
                }
                if (!meta.getDependencies().isEmpty()) {
                    LOGGER.info("Plugin {} requires dependencies: {}", pluginId, meta.getDependencies());
                }
            } catch (JsonSyntaxException e) {
                LOGGER.error("Invalid JSON format in {}", metaFile, e);
            } catch (IOException e) {
                LOGGER.error("Failed to read {}", metaFile, e);
            }
        }

        return new PyPluginDescriptor(pluginId, pluginName, pluginRoot);
    }

    /**
     * 获取所有已加载插件
     */
    public static Map<String, PyPluginDescriptor> getLoadedPlugins() {
        return new HashMap<>(loadedPlugins);
    }

    /**
     * 重新加载指定插件
     */
    public static void reloadPlugin(String pluginId) {
        PyPluginDescriptor descriptor = loadedPlugins.get(pluginId);
        if (descriptor != null) {
            loadedPlugins.remove(pluginId);
            loadPlugin(descriptor.scriptPath);
        }
    }
}
