package com.axis.innovators.box;

import com.axis.innovators.box.events.GlobalEventBus;
import com.axis.innovators.box.events.SettingsLoadEvents;
import com.axis.innovators.box.events.StartupEvent;
import com.axis.innovators.box.events.SubscribeEvent;
import com.axis.innovators.box.gui.*;
import com.axis.innovators.box.plugins.PluginDescriptor;
import com.axis.innovators.box.plugins.PluginLoader;
import com.axis.innovators.box.register.RegistrationTool;
import com.axis.innovators.box.tools.LibraryLoad;
import com.axis.innovators.box.tools.SystemInfoUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.tzd.lm.LM;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.Enumeration;
import java.util.List;

/**
 * 主类
 * @author tzdwindows 7
 */
public class Main {
    private static final Logger logger = LogManager.getLogger(Main.class);
    private static final String VERSIONS = "0.0.1";
    private static final String[] AUTHOR = new String[]{
            "tzdwindows 7"
    };

    /** 我是总任务数 **/
    public int totalTasks = 1;
    /** 我是当前任务数 **/
    private int completedTasks = 0;
    public ProgressBarManager progressBarManager = new ProgressBarManager("加载中...", totalTasks);
    private static Main main;
    private MainWindow ex;
    private Thread thread;
    private final String[] args;
    private boolean isWindow = false;
    private final RegistrationTool registrationTool = new RegistrationTool(this);

    public Main(String[] args){
        this.args = args;
    }

    static {
        try {
            LibraryLoad.loadLibrary("FridaNative");
            LM.loadLibrary(LM.CUDA);
        } catch (Exception e) {
            logger.error("Failed to load the 'FridaNative' library", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取主类
     * @return 主类
     */
    public static Main getMain() {
        return main;
    }

    /**
     * 获取主窗口
     * @return 主窗口
     */
    public MainWindow getMainWindow() {
        return ex;
    }

    /**
     * 退出程序
     */
    public void quit() {
        logger.info("Application is shutting down...");
        thread.interrupt();
        System.exit(0);
    }

    public void initLog4j2() {
        Log4j2OutputStream.redirectSystemStreams();
        // 输出版本和作者信息
        logger.info("Application Version: {}", VERSIONS);
        logger.info("Authors: {}", String.join(", ", AUTHOR));

        // 输出系统信息
        logger.info("Operating System: {}", SystemInfoUtil.getOSName());
        logger.info("OS Architecture: {}", SystemInfoUtil.getOSArch());
        logger.info("CPU: {}", SystemInfoUtil.getCPUInfo());
        logger.info("GPU: {}", SystemInfoUtil.getGPUInfo());
        logger.info("Java Version: {}", System.getProperty("java.version"));
        logger.info("Java Vendor: {}", System.getProperty("java.vendor"));
        logger.info("Java Home: {}", System.getProperty("java.home"));
        logger.info("Java Class Path: {}", System.getProperty("java.class.path"));
        logger.info("ClassLoader.getSystemClassLoader(): {}", ClassLoader.getSystemClassLoader());
    }

    @SubscribeEvent
    public void onSettingsLoad(SettingsLoadEvents event) {
        JTabbedPane tabbedPane = new JTabbedPane();

        JPanel pluginPanel = createPluginSettingsPanel();
        tabbedPane.addTab("插件", null, pluginPanel, "插件管理");

        JPanel generalPanel = createGeneralSettingsPanel();
        tabbedPane.addTab("基础设置", null, generalPanel, "外观设置");

        JPanel aboutPanel = createAboutPanel();
        tabbedPane.addTab("关于", null, aboutPanel, "版本信息");

        event.content().add(tabbedPane, BorderLayout.CENTER);
    }

    private JPanel createAboutPanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

        JTextArea infoArea = new JTextArea();
        infoArea.setEditable(false);
        infoArea.setLineWrap(true);
        infoArea.setWrapStyleWord(true);
        infoArea.append("软件版本: " + Main.VERSIONS + "\n\n");
        infoArea.append("开发作者:\n");
        for (String author : Main.AUTHOR) {
            infoArea.append("• " + author + "\n");
        }

        panel.add(new JScrollPane(infoArea), BorderLayout.CENTER);
        return panel;
    }

    // 字体选择器内部类
    private static class FontChooser extends JPanel {
        private final JComboBox<String> fontFamilyCombo;
        private final JSpinner fontSizeSpinner;

        public FontChooser(Font currentFont) {
            setLayout(new GridLayout(2, 2, 5, 5));

            // 字体族选择
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
            String[] fontFamilies = ge.getAvailableFontFamilyNames();
            fontFamilyCombo = new JComboBox<>(fontFamilies);
            fontFamilyCombo.setSelectedItem(currentFont.getFamily());

            // 字体大小选择
            SpinnerNumberModel sizeModel = new SpinnerNumberModel(
                    currentFont.getSize(), 8, 48, 1
            );
            fontSizeSpinner = new JSpinner(sizeModel);

            add(new JLabel("字体："));
            add(fontFamilyCombo);
            add(new JLabel("大小："));
            add(fontSizeSpinner);
        }

        public Font getSelectedFont() {
            return new Font(
                    (String) fontFamilyCombo.getSelectedItem(),
                    Font.PLAIN,
                    (Integer) fontSizeSpinner.getValue()
            );
        }
    }

    // 应用主题颜色
    private void applyThemeColor(Color color) {
        // 更新全局颜色设置
        UIManager.put("Panel.background", color);
        UIManager.put("TabbedPane.background", color);

        // 更新现有界面
        SwingUtilities.updateComponentTreeUI(Main.getMain().getMainWindow());
    }

    private JPanel createPluginSettingsPanel() {
        JPanel panel = new JPanel(new BorderLayout());

        // 表格列配置
        String[] columns = {"插件名称", "版本支持", "描述"};
        DefaultTableModel model = new DefaultTableModel(columns, 0) {
            @Override
            public boolean isCellEditable(int row, int column) {
                return false; // 禁止编辑
            }
        };

        // 从PluginLoader获取插件数据
        List<PluginDescriptor> plugins = PluginLoader.getLoadedPlugins();
        for (PluginDescriptor plugin : plugins) {
            model.addRow(new Object[]{
                    plugin.getName(),
                    String.join(", ", plugin.getSupportedVersions()),
                    plugin.getDescription()
            });
        }

        JTable table = new JTable(model);
        table.setRowHeight(30);
        table.getTableHeader().setFont(new Font("微软雅黑", Font.BOLD, 14));

        // 添加滚动面板
        JScrollPane scrollPane = new JScrollPane(table);
        scrollPane.setBorder(BorderFactory.createTitledBorder("已加载插件列表"));
        panel.add(scrollPane, BorderLayout.CENTER);

        return panel;
    }

    private JPanel createGeneralSettingsPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5, 5, 5, 5);
        gbc.anchor = GridBagConstraints.WEST;

        // 颜色选择组件
        gbc.gridx = 0;
        gbc.gridy = 0;
        panel.add(new JLabel("界面主题颜色："), gbc);

        JButton colorBtn = new JButton("选择颜色");
        colorBtn.addActionListener(e -> {
            Color color = JColorChooser.showDialog(panel, "选择主题颜色", Color.WHITE);
            if (color != null) {
                applyThemeColor(color);
            }
        });
        gbc.gridx = 1;
        panel.add(colorBtn, gbc);

        // 字体选择组件
        gbc.gridy++;
        gbc.gridx = 0;
        panel.add(new JLabel("界面字体："), gbc);

        JButton fontBtn = new JButton("选择字体");
        fontBtn.addActionListener(e -> {
            Font currentFont = UIManager.getFont("Label.font");
            FontChooser fontChooser = new FontChooser(currentFont);
            int result = JOptionPane.showConfirmDialog(
                    panel,
                    fontChooser,
                    "选择字体",
                    JOptionPane.OK_CANCEL_OPTION
            );

            if (result == JOptionPane.OK_OPTION) {
                applyUIFont(fontChooser.getSelectedFont());
            }
        });
        gbc.gridx = 1;
        panel.add(fontBtn, gbc);

        // 添加CUDA选项
        gbc.gridy++;
        gbc.gridx = 0;
        panel.add(new JLabel("AI推理时使用CUDA："), gbc);

        JCheckBox cudaCheckBox = new JCheckBox("启用CUDA加速", LM.CUDA);
        cudaCheckBox.addActionListener(e -> {
            boolean useCUDA = cudaCheckBox.isSelected();
            LM.CUDA = useCUDA;
            logger.info("CUDA加速设置已更新: " + (useCUDA ? "启用" : "禁用"));

            try {
                LM.loadLibrary(useCUDA);
                logger.info("AI推理库已重新加载");
            } catch (Exception ex) {
                logger.error("无法重新加载AI推理库", ex);
                JOptionPane.showMessageDialog(panel, "无法重新加载AI推理库，请检查CUDA环境", "错误", JOptionPane.ERROR_MESSAGE);
            }
        });
        gbc.gridx = 1;
        panel.add(cudaCheckBox, gbc);

        return panel;
    }

    // 应用全局字体
    private void applyUIFont(Font font) {
        Enumeration<Object> keys = UIManager.getLookAndFeelDefaults().keys();
        while (keys.hasMoreElements()) {
            Object key = keys.nextElement();
            Object value = UIManager.get(key);
            if (value instanceof Font) {
                Font derived = font.deriveFont(((Font)value).getStyle());
                UIManager.put(key, derived);
            }
        }

        // 更新所有窗口
        for (Window window : Window.getWindows()) {
            SwingUtilities.updateComponentTreeUI(window);
        }
    }

    public static void main(String[] args) {
        main = new Main(args);
        // 注册事件
        GlobalEventBus.EVENT_BUS.register(main);

        main.initLog4j2();

        // 设置系统外观
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
            logger.warn("Failed to load the system facade class", e);
        }
        main.thread = new Thread(() -> {
            try {
                // 主任务1：加载插件
                logger.info("Loaded plugins Started");
                main.progressBarManager.updateMainProgress(++main.completedTasks);
                PluginLoader.loadPlugins();
                logger.info("Loaded plugins End");

                main.progressBarManager.close();

                SwingUtilities.invokeLater(() -> {
                    try {
                        main.ex = new MainWindow();
                        GlobalEventBus.EVENT_BUS.post(new StartupEvent(main));
                        main.runWindow();
                    } catch (Exception e) {
                        logger.error("There was a problem starting the main thread", e);
                        throw new RuntimeException(e);
                    }
                });
            } catch (Exception e) {
                logger.error("Failed to load plugins", e);
                throw new RuntimeException(e);
            }
        });
        main.thread.setName("Main Thread");
        main.thread.start();
    }

    public void runWindow() {
        progressBarManager.updateMainProgress(++completedTasks);

        if (!registrationTool.getToolCategories().isEmpty()) {
            for (int i = 0; i < registrationTool.getToolCategories()
                    .size(); i++) {
                ex.addToolCategory(registrationTool.getToolCategories()
                        .get(i));
                progressBarManager.updateSubProgress(
                        "add tools", i,
                        registrationTool.getToolCategories().size());
            }
        }

        ex.initUI();
        isWindow = true;
        ex.setVisible(true);
    }

    /**
     * 获取注册工具
     * @return 注册工具
     */
    public RegistrationTool getRegistrationTool() {
        return registrationTool;
    }

    /**
     * 获取命令行参数
     * @return 命令行参数
     */
    public String[] getArgs() {
        return args;
    }

    public boolean isWindow() {
        return isWindow;
    }
}