package com.axis.innovators.box.gui;

import com.axis.innovators.box.gui.renderer.DarculaCompletionCellRenderer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.fife.rsta.ac.LanguageSupport;
import org.fife.rsta.ac.LanguageSupportFactory;
import org.fife.rsta.ac.perl.PerlLanguageSupport;
import org.fife.ui.autocomplete.*;
import org.fife.ui.rsyntaxtextarea.folding.CurlyFoldParser;
import org.fife.ui.rsyntaxtextarea.folding.FoldParserManager;
import org.tzd.frida.windows.Frida;

import org.fife.ui.rsyntaxtextarea.*;
import org.fife.ui.rtextarea.RTextScrollPane;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
import java.util.function.Consumer;
import java.util.prefs.Preferences;

/**
 * Frida注入工具窗口
 * @author tzdwindows 7
 */
public class FridaWindow extends WindowsJDialog {
    private static final Logger logger = LogManager.getLogger(FridaWindow.class);
    private RSyntaxTextArea scriptArea;
    private JTextArea logArea;
    private boolean isRepetition = false;
    private JComboBox<ProcessInfo> processCombo;
    private JTextField pidField;
    // IDEA风格配色
    private static final Color BACKGROUND = new Color(0x2B2B2B);
    private static final Color SELECTION_COLOR = new Color(0x214283);
    private JDialog settingsDialog;

    public FridaWindow(Window owner) {
        super(owner, language.getText("fridaWindow.title"), ModalityType.APPLICATION_MODAL);
        initUI();
    }

    static {
        Font chineseFont = new Font("Microsoft YaHei", Font.PLAIN, 13);
        UIManager.put("Menu.font", chineseFont);
        UIManager.put("MenuItem.font", chineseFont);
        UIManager.put("Button.font", chineseFont);
        UIManager.put("ComboBox.font", chineseFont);
    }

    @Override
    public void initUI() {
        super.initUI();
        setSize(1280, 800);
        setLocationRelativeTo(getOwner());
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);

        JPanel mainPanel = new JPanel(new BorderLayout());
        mainPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
        mainPanel.setBackground(BACKGROUND);

        pidField = new JTextField();
        styleTextField(pidField, "输入PID或进程名");
        mainPanel.add(pidField, BorderLayout.CENTER);

        // 输入面板
        JPanel inputPanel = createInputPanel();
        mainPanel.add(inputPanel, BorderLayout.NORTH);

        // 中心区域（代码编辑器和日志）
        JSplitPane centerSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
        centerSplit.setDividerLocation(500);
        centerSplit.setContinuousLayout(true);

        // 脚本编辑器
        JPanel scriptPanel = createScriptPanel();
        centerSplit.setTopComponent(scriptPanel);

        // 日志输出
        JPanel logPanel = createLogPanel();
        centerSplit.setBottomComponent(logPanel);

        mainPanel.add(centerSplit, BorderLayout.CENTER);
        createMenuBar();
        setContentPane(mainPanel);

        addWindowListener(new WindowAdapter() {
            @Override
            public void windowOpened(WindowEvent e) {
                scriptArea.requestFocusInWindow();
            }
        });
    }

    private void createMenuBar() {
        JMenuBar menuBar = new JMenuBar();
        // 菜单栏深色背景
        menuBar.setBackground(new Color(0x3C3F41));
        menuBar.setBorder(BorderFactory.createEmptyBorder(2, 0, 2, 0));

        // 统一设置菜单UI属性
        UIManager.put("Menu.background", new Color(0x3C3F41));
        UIManager.put("Menu.foreground", new Color(0xBBBBBB));
        UIManager.put("MenuItem.background", new Color(0x3C3F41));
        UIManager.put("MenuItem.foreground", new Color(0xBBBBBB));
        UIManager.put("MenuItem.selectionBackground", new Color(0x214283));

        // 文件菜单
        JMenu fileMenu = new JMenu(language.getText("fridaWindow.menu"));
        styleMenu(fileMenu);

        // 退出菜单项
        JMenuItem exitItem = new JMenuItem(language.getText("fridaWindow.menu.exit"));
        styleMenuItem(exitItem);
        exitItem.addActionListener(e -> dispose());

        JMenuItem openItem = new JMenuItem(language.getText("fridaWindow.menu.open"));
        styleMenuItem(openItem);
        openItem.addActionListener(e -> openFile());

        JMenuItem saveItem = new JMenuItem(language.getText("fridaWindow.menu.save"));
        styleMenuItem(saveItem);
        saveItem.addActionListener(e -> saveFile());

        fileMenu.add(exitItem);
        fileMenu.add(openItem);
        fileMenu.add(saveItem);

        // 帮助菜单
        JMenu helpMenu = new JMenu(language.getText("fridaWindow.menu.help"));
        styleMenu(helpMenu);

        // 设置菜单
        JMenu settingsMenu = new JMenu(language.getText("fridaWindow.menu.settingsMenu"));
        styleMenu(fileMenu);

        JMenuItem settingsItem = new JMenuItem(language.getText("fridaWindow.menu.settingsMenu.settingsItem"));
        styleMenuItem(settingsItem);
        settingsItem.addActionListener(e -> settingsWindow());
        settingsMenu.add(settingsItem);

        // 关于菜单项
        JMenuItem aboutItem = new JMenuItem(language.getText("fridaWindow.menu.help.about"));
        styleMenuItem(aboutItem);
        aboutItem.addActionListener(e -> showAboutDialog());

        helpMenu.add(aboutItem);

        menuBar.add(fileMenu);
        menuBar.add(settingsMenu);
        menuBar.add(helpMenu);
        setJMenuBar(menuBar);
    }

    private void styleTextField(JTextField field, String placeholder) {
        field.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12));
        field.setBackground(new Color(0x3C3F41));
        field.setForeground(Color.WHITE);
        field.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createLineBorder(new Color(0x515658)),
                BorderFactory.createEmptyBorder(5, 8, 5, 8)
        ));
        field.putClientProperty("JTextField.placeholderText", placeholder);
    }

    private JPanel createInputPanel() {
        JPanel panel = new JPanel(new BorderLayout(10, 0));
        panel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
        panel.setOpaque(false);

        // 进程组合框
        processCombo = new JComboBox<>();
        styleComboBox(processCombo);

        // 操作工具栏
        JPanel controlPanel = new JPanel(new GridLayout(1, 2, 8, 0));
        controlPanel.setOpaque(false);

        JButton injectBtn = createModernButton(language.getText("fridaWindow.button.inject"), 0x6897BB);
        JButton stopBtn = createModernButton(language.getText("fridaWindow.button.inject.pid"), 0xD25252);

        injectBtn.addActionListener(this::handleInject);
        stopBtn.addActionListener(this::openProcessSelectionWindow);

        controlPanel.add(injectBtn);
        controlPanel.add(stopBtn);

        panel.add(processCombo, BorderLayout.CENTER);
        panel.add(controlPanel, BorderLayout.EAST);

        return panel;
    }

    private JButton createModernButton(String text, int color) {
        JButton btn = new JButton(text);
        btn.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12));
        btn.setFocusPainted(false);
        btn.setBackground(new Color(color));
        btn.setForeground(Color.WHITE);
        btn.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createLineBorder(new Color(color).darker(), 1),
                BorderFactory.createEmptyBorder(6, 15, 6, 15)
        ));

        // 悬停效果
        btn.addMouseListener(new MouseAdapter() {
            public void mouseEntered(MouseEvent e) {
                btn.setBackground(new Color(color).brighter());
            }

            public void mouseExited(MouseEvent e) {
                btn.setBackground(new Color(color));
            }
        });
        return btn;
    }

    private void settingsWindow() {
        settingsDialog = new JDialog(this, "编辑器设置", true);
        settingsDialog.setSize(600, 450);
        settingsDialog.setLocationRelativeTo(this);

        JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
        mainPanel.setBorder(new EmptyBorder(10, 10, 10, 10));

        // 配置选项面板
        JTabbedPane tabbedPane = new JTabbedPane();

        // 颜色设置面板
        JPanel colorPanel = createColorSettingsPanel();
        tabbedPane.addTab("语法颜色", colorPanel);

        // 字体设置面板
        JPanel fontPanel = createFontSettingsPanel();
        tabbedPane.addTab("字体设置", fontPanel);

        // 底部按钮
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        JButton saveBtn = createModernButton("保存", 0x6897BB);
        JButton defaultBtn = createModernButton("恢复默认", 0x808080);
        JButton cancelBtn = createModernButton("取消", 0xD25252);

        saveBtn.addActionListener(e -> applyAndSaveSettings());
        defaultBtn.addActionListener(e -> restoreDefaultSettings());
        cancelBtn.addActionListener(e -> settingsDialog.dispose());

        buttonPanel.add(defaultBtn);
        buttonPanel.add(cancelBtn);
        buttonPanel.add(saveBtn);

        mainPanel.add(tabbedPane, BorderLayout.CENTER);
        mainPanel.add(buttonPanel, BorderLayout.SOUTH);

        settingsDialog.setContentPane(mainPanel);
        settingsDialog.setVisible(true);
    }

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

        // 使用LinkedHashMap保持顺序
        Map<String, Integer> tokenConfig = new LinkedHashMap<>();
        tokenConfig.put("关键字（Frida）", Token.RESERVED_WORD);
        tokenConfig.put("标准库函数", Token.RESERVED_WORD_2);
        tokenConfig.put("内置函数", Token.FUNCTION);
        tokenConfig.put("字符串", Token.LITERAL_STRING_DOUBLE_QUOTE);
        tokenConfig.put("数字", Token.LITERAL_NUMBER_DECIMAL_INT);
        tokenConfig.put("注释", Token.COMMENT_EOL);
        tokenConfig.put("运算符", Token.OPERATOR);
        tokenConfig.put("标识符", Token.IDENTIFIER);
        tokenConfig.put("分隔符", Token.SEPARATOR);
        tokenConfig.put("正则表达式", Token.REGEX);

        DefaultTableModel model = new DefaultTableModel(new Object[]{"语法元素", "颜色示例"}, 0);
        for (Map.Entry<String, Integer> entry : tokenConfig.entrySet()) {
            Style style = scriptArea.getSyntaxScheme().getStyle(entry.getValue());
            model.addRow(new Object[]{entry.getKey(), style.foreground});
        }

        JTable colorTable = new JTable(model);
        colorTable.setRowHeight(30);
        colorTable.getColumnModel().getColumn(1).setCellRenderer(new ColorRenderer());
        colorTable.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                int column = colorTable.columnAtPoint(e.getPoint());
                if (e.getClickCount() == 1 && column == 1) {
                    int row = colorTable.rowAtPoint(e.getPoint());
                    Color current = (Color) colorTable.getValueAt(row, 1);
                    Color newColor = JColorChooser.showDialog(settingsDialog,
                            "选择颜色", current);
                    if (newColor != null) {
                        colorTable.setValueAt(newColor, row, 1);
                    }
                }
            }
        });

        JScrollPane scrollPane = new JScrollPane(colorTable);
        panel.add(scrollPane, BorderLayout.CENTER);

        // 保存颜色配置引用
        panel.putClientProperty("tokenConfig", tokenConfig);
        panel.putClientProperty("colorTable", colorTable);

        return panel;
    }

    private JPanel createFontSettingsPanel() {
        JPanel panel = new JPanel(new GridLayout(0, 2, 10, 10));

        // 字体名称
        String[] fontNames = GraphicsEnvironment.getLocalGraphicsEnvironment()
                .getAvailableFontFamilyNames();
        JComboBox<String> fontCombo = new JComboBox<>(fontNames);
        fontCombo.setSelectedItem(scriptArea.getFont().getFamily());

        // 字体样式
        JCheckBox boldCheck = new JCheckBox("粗体");
        JCheckBox italicCheck = new JCheckBox("斜体");

        // 字号
        SpinnerModel sizeModel = new SpinnerNumberModel(
                scriptArea.getFont().getSize(), 8, 48, 1);
        JSpinner sizeSpinner = new JSpinner(sizeModel);

        panel.add(new JLabel("字体名称："));
        panel.add(fontCombo);
        panel.add(new JLabel("字号："));
        panel.add(sizeSpinner);
        panel.add(new JLabel("样式："));
        JPanel stylePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        stylePanel.add(boldCheck);
        stylePanel.add(italicCheck);
        panel.add(stylePanel);

        // 预览区域
        JTextArea preview = new JTextArea("Frida示例代码：\nJava.perform(() => {\n  // 注释\n  console.log('Hello');\n for (var i = 0; i < 10; i++) {\n" +
                "            \n" +
                "}});");
        preview.setFont(scriptArea.getFont());
        preview.setEditable(false);
        preview.setBackground(scriptArea.getBackground());
        preview.setForeground(scriptArea.getForeground());

        // 监听变化
        fontCombo.addActionListener(e -> updateFontPreview(fontCombo, sizeSpinner, boldCheck, italicCheck, preview));
        sizeSpinner.addChangeListener(e -> updateFontPreview(fontCombo, sizeSpinner, boldCheck, italicCheck, preview));
        boldCheck.addActionListener(e -> updateFontPreview(fontCombo, sizeSpinner, boldCheck, italicCheck, preview));
        italicCheck.addActionListener(e -> updateFontPreview(fontCombo, sizeSpinner, boldCheck, italicCheck, preview));

        panel.add(new JLabel("预览："));
        panel.add(new JScrollPane(preview));

        // 保存控件引用
        panel.putClientProperty("fontCombo", fontCombo);
        panel.putClientProperty("sizeSpinner", sizeSpinner);
        panel.putClientProperty("boldCheck", boldCheck);
        panel.putClientProperty("italicCheck", italicCheck);

        return panel;
    }

    private void updateFontPreview(JComboBox<String> fontCombo, JSpinner sizeSpinner,
                                   JCheckBox boldCheck, JCheckBox italicCheck, JTextArea preview) {
        String fontName = (String) fontCombo.getSelectedItem();
        int size = (Integer) sizeSpinner.getValue();
        int style = Font.PLAIN;
        if (boldCheck.isSelected()) style |= Font.BOLD;
        if (italicCheck.isSelected()) style |= Font.ITALIC;
        Font newFont = new Font(fontName, style, size);
        preview.setFont(newFont);
    }

    private void applyAndSaveSettings() {
        // 应用颜色设置
        JPanel colorPanel = (JPanel) ((JTabbedPane)settingsDialog.getContentPane()
                .getComponent(0)).getComponent(0);

        Map<String, Integer> tokenConfig = (Map<String, Integer>) colorPanel.getClientProperty("tokenConfig");
        JTable colorTable = (JTable) colorPanel.getClientProperty("colorTable");

        SyntaxScheme scheme = scriptArea.getSyntaxScheme();
        for (int i = 0; i < colorTable.getRowCount(); i++) {
            String tokenName = (String) colorTable.getValueAt(i, 0);
            Color color = (Color) colorTable.getValueAt(i, 1);
            Integer tokenType = tokenConfig.get(tokenName);
            if (tokenType != null) {
                scheme.getStyle(tokenType).foreground = color;
            }
        }

        // 应用字体设置
        JPanel fontPanel = (JPanel) ((JTabbedPane)settingsDialog.getContentPane()
                .getComponent(0)).getComponent(1);

        JComboBox<String> fontCombo = (JComboBox<String>) fontPanel.getClientProperty("fontCombo");
        JSpinner sizeSpinner = (JSpinner) fontPanel.getClientProperty("sizeSpinner");
        JCheckBox boldCheck = (JCheckBox) fontPanel.getClientProperty("boldCheck");
        JCheckBox italicCheck = (JCheckBox) fontPanel.getClientProperty("italicCheck");

        String fontName = (String) fontCombo.getSelectedItem();
        int size = (Integer) sizeSpinner.getValue();
        int style = Font.PLAIN;
        if (boldCheck.isSelected()) style |= Font.BOLD;
        if (italicCheck.isSelected()) style |= Font.ITALIC;
        Font newFont = new Font(fontName, style, size);
        scriptArea.setFont(newFont);

        // 保存到首选项
        Preferences prefs = Preferences.userNodeForPackage(FridaWindow.class);
        prefs.putInt("editor.font.style", style);
        prefs.putInt("editor.font.size", size);
        prefs.put("editor.font.name", fontName);

        settingsDialog.dispose();
        scriptArea.repaint();
    }

    private void restoreDefaultSettings() {
        // 恢复颜色默认
        configureIDEATheme(scriptArea.getSyntaxScheme());

        // 恢复字体默认
        Font defaultFont = new Font("JetBrains Mono", Font.PLAIN, 13);
        if (!Arrays.asList(GraphicsEnvironment.getLocalGraphicsEnvironment()
                .getAvailableFontFamilyNames()).contains("JetBrains Mono")) {
            defaultFont = new Font("Consolas", Font.PLAIN, 14);
        }
        scriptArea.setFont(defaultFont);

        // 清除首选项存储
        Preferences prefs = Preferences.userNodeForPackage(FridaWindow.class);
        prefs.remove("editor.font.name");
        prefs.remove("editor.font.style");
        prefs.remove("editor.font.size");

        settingsDialog.dispose();
        scriptArea.repaint();
    }

    // 自定义表格渲染器用于显示颜色
    private static class ColorRenderer extends DefaultTableCellRenderer {
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value,
                                                       boolean isSelected, boolean hasFocus, int row, int column) {
            Component c = super.getTableCellRendererComponent(table, value,
                    isSelected, hasFocus, row, column);
            if (value instanceof Color) {
                setText("");
                setBackground((Color) value);
                setBorder(BorderFactory.createLineBorder(Color.GRAY));
            }
            return c;
        }
    }

    private void styleComboBox(JComboBox<?> combo) {
        combo.setRenderer(new DefaultListCellRenderer() {
            @Override
            public Component getListCellRendererComponent(JList<?> list, Object value,
                                                          int index, boolean isSelected, boolean cellHasFocus) {
                super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
                setBackground(isSelected ? new Color(0x214283) : new Color(0x3C3F41));
                setForeground(Color.WHITE);
                return this;
            }
        });
    }


    private void openFile() {
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter("Frida脚本配置 (*.frida)", "frida"));
        int result = fileChooser.showOpenDialog(this);
        if (result == JFileChooser.APPROVE_OPTION) {
            try (BufferedReader reader = new BufferedReader(new FileReader(fileChooser.getSelectedFile()))) {
                String pid = reader.readLine();
                StringBuilder script = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    script.append(line).append("\n");
                }
                pidField.setText(pid);
                scriptArea.setText(script.toString());
            } catch (IOException ex) {
                logger.error("文件打开失败", ex);
                JOptionPane.showMessageDialog(this,
                        "无法加载文件: " + ex.getMessage(),
                        "IO错误",
                        JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    private void saveFile() {
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter("Frida脚本配置 (*.frida)", "frida"));
        int result = fileChooser.showSaveDialog(this);
        if (result == JFileChooser.APPROVE_OPTION) {
            File file = fileChooser.getSelectedFile();
            if (!file.getName().toLowerCase().endsWith(".frida")) {
                file = new File(file.getParentFile(), file.getName() + ".frida");
            }
            try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
                writer.write(pidField.getText());
                writer.newLine();
                writer.write(scriptArea.getText());
            } catch (IOException ex) {
                logger.error("文件保存失败", ex);
                JOptionPane.showMessageDialog(this,
                        "无法保存文件: " + ex.getMessage(),
                        "IO错误",
                        JOptionPane.ERROR_MESSAGE);
            }
        }
    }


    private void styleMenu(JMenu menu) {
        menu.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12));
        menu.setForeground(new Color(0xBBBBBB));
        menu.setBorder(BorderFactory.createEmptyBorder(5, 8, 5, 8));
        menu.setOpaque(true);
        menu.setBackground(new Color(0x3C3F41));
    }

    private void styleMenuItem(JMenuItem item) {
        item.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12));
        item.setForeground(new Color(0xBBBBBB));
        item.setBackground(new Color(0x3C3F41));
        item.setBorder(BorderFactory.createEmptyBorder(5, 20, 5, 10)); // 增加左侧间距
        item.setOpaque(true);

        // 鼠标悬停效果
        item.addMouseListener(new MouseAdapter() {
            public void mouseEntered(MouseEvent e) {
                item.setBackground(new Color(0x515658));
            }

            public void mouseExited(MouseEvent e) {
                item.setBackground(new Color(0x3C3F41));
            }
        });
    }

    private void showAboutDialog() {
        JDialog aboutDialog = new JDialog(this, "关于", true);
        aboutDialog.setSize(300, 200);
        aboutDialog.setLocationRelativeTo(this);

        JPanel content = new JPanel(new BorderLayout());
        content.setBorder(new EmptyBorder(20, 20, 20, 20));

        JLabel title = new JLabel("Frida Injector v2.0");
        title.setFont(new Font("Segoe UI", Font.BOLD, 16));

        JTextArea info = new JTextArea("基于Frida的现代注入工具\n\nCopyright ? 2024");
        info.setEditable(false);

        content.add(title, BorderLayout.NORTH);
        content.add(info, BorderLayout.CENTER);

        aboutDialog.setContentPane(content);
        aboutDialog.setVisible(true);
    }

    private JPanel createScriptPanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createTitledBorder("Frida脚本编辑器"));

        scriptArea = new RSyntaxTextArea();
        LanguageSupportFactory lsf = LanguageSupportFactory.get();
        LanguageSupport support = lsf.
                getSupportFor(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT);
        support.install(scriptArea);

        scriptArea.setCodeFoldingEnabled(true);
        FoldParserManager.get().addFoldParserMapping("text/javascript", new CurlyFoldParser());

        scriptArea.setFractionalFontMetricsEnabled(true);
        scriptArea.setAutoIndentEnabled(true);

        scriptArea.setCodeFoldingEnabled(true);
        scriptArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT);
        scriptArea.setAntiAliasingEnabled(true);
        scriptArea.setTabSize(4);
        scriptArea.setCaretPosition(0);
        scriptArea.setSelectionColor(SELECTION_COLOR);
        scriptArea.setMarkOccurrences(true);
        scriptArea.setBracketMatchingEnabled(true);
        setupAutoCompletion();

        Font ideaFont = new Font("JetBrains Mono", Font.PLAIN, 13);
        if (!Arrays.asList(GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()).contains("JetBrains Mono")) {
            ideaFont = new Font("Consolas", Font.PLAIN, 14);
        }
        scriptArea.setFont(ideaFont);

        scriptArea.setBackground(new Color(0x1E1F22));
        scriptArea.setSelectionColor(new Color(0x214283));
        scriptArea.setCurrentLineHighlightColor(new Color(0x323232));

        SyntaxScheme scheme = new SyntaxScheme(true);
        scheme = configureIDEATheme(scheme);
        scriptArea.setSyntaxScheme(scheme);

        RTextScrollPane scrollPane = new RTextScrollPane(scriptArea);
        scrollPane.setBorder(BorderFactory.createLineBorder(new Color(0x3C3F41)));
        scrollPane.setFoldIndicatorEnabled(true);

        panel.add(scrollPane);

        return panel;
    }

    private SyntaxScheme configureIDEATheme(SyntaxScheme scheme) {
        // 基础颜色配置
        Color background = new Color(0x2B2B2B); // 背景色
        Color foreground = new Color(0xE0E0E0); // 前景色（默认文本颜色）

        // 设置全局默认样式
        Style defaultStyle = scheme.getStyle(Token.NULL);
        defaultStyle.foreground = foreground;
        defaultStyle.background = background;

        // ======== JavaScript 标准库配置 ========
        // console 相关 API
        setTokenStyle(scheme, Token.RESERVED_WORD_2, 0xCC7832); // 橙色
        setTokenStyle(scheme, Token.FUNCTION, 0xFFC66D); // 黄色

        // ======== Frida 关键字和 API 配置 ========
        // Frida 关键字（如 Java.perform, Interceptor.attach 等）
        setTokenStyle(scheme, Token.RESERVED_WORD, 0xCC7832); // 橙色

        // Frida API（如 Java, Module, Memory 等）
        setTokenStyle(scheme, Token.FUNCTION, 0xFFC66D); // 黄色

        // 字符串
        setTokenStyle(scheme, Token.LITERAL_STRING_DOUBLE_QUOTE, 0x6A8759); // 绿色

        // 数字
        setTokenStyle(scheme, Token.LITERAL_NUMBER_DECIMAL_INT, 0x6897BB); // 蓝色

        // 注释
        setTokenStyle(scheme, Token.COMMENT_EOL, 0x629755); // 浅绿色
        setTokenStyle(scheme, Token.COMMENT_MULTILINE, 0x629755); // 浅绿色
        setTokenStyle(scheme, Token.COMMENT_DOCUMENTATION, 0x629755); // 浅绿色

        // 运算符
        setTokenStyle(scheme, Token.OPERATOR, 0xFFD700); // 金色

        // 标识符（变量名、函数名等）
        setTokenStyle(scheme, Token.IDENTIFIER, 0xE0E0E0); // 白色

        // 分隔符（如括号、逗号等）
        setTokenStyle(scheme, Token.SEPARATOR, 0x4EC9B0); // 青色

        // 正则表达式
        setTokenStyle(scheme, Token.REGEX, 0xD25252); // 红色

        // ======== 跨语言通用配置 ========
        // XML/HTML 标签（如果有需要）
        setTokenStyle(scheme, Token.MARKUP_TAG_NAME, 0xE8BF6A); // 浅黄色
        setTokenStyle(scheme, Token.MARKUP_TAG_DELIMITER, 0xCC7832); // 橙色
        setTokenStyle(scheme, Token.MARKUP_ENTITY_REFERENCE, 0x6897BB); // 蓝色

        // 设置当前行高亮
        scriptArea.setHighlightCurrentLine(true);
        scriptArea.setCurrentLineHighlightColor(new Color(0x323232));

        return scheme;
    }


    private void setTokenStyle(SyntaxScheme scheme, int tokenType, int rgb) {
        Style style = scheme.getStyle(tokenType);
        style.foreground = new Color(rgb);
    }

    private JPanel createLogPanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createTitledBorder("日志输出"));

        logArea = new JTextArea();
        logArea.setEditable(false);
        logArea.setFont(new Font("Consolas", Font.PLAIN, 12));
        logArea.setBackground(new Color(0x1E1E1E));
        logArea.setForeground(Color.WHITE);

        JScrollPane scrollPane = new JScrollPane(logArea);
        scrollPane.setBorder(BorderFactory.createLineBorder(new Color(0x3C3F41)));

        panel.add(scrollPane);
        return panel;
    }

    private void setupAutoCompletion() {
        try {
            CompletionProvider provider = createCompletionProvider();
            AutoCompletion ac = new AutoCompletion(provider);

            ac.setAutoActivationEnabled(true);
            ac.setParameterAssistanceEnabled(true);
            ac.setShowDescWindow(true);
            ac.setListCellRenderer(new DarculaCompletionCellRenderer());

            ac.install(scriptArea);
            ac.setDescriptionWindowColor(new Color(0x323232));
            scriptArea.addKeyListener(new KeyAdapter() {
                @Override
                public void keyTyped(KeyEvent e) {
                    char keyChar = e.getKeyChar();
                    if (Character.isLetterOrDigit(keyChar)) {
                        SwingUtilities.invokeLater(ac::doCompletion);
                    }
                }
            });
        } catch (Exception e) {
            logger.error("Autocompletion failed to initialize ", e);
        }
    }

    private CompletionProvider createCompletionProvider() {
        DefaultCompletionProvider provider = new DefaultCompletionProvider();
        FridaSyntax.addFridaCompletions(provider);
        FridaSyntax.addBasicCompletions(provider);
        return provider;
    }

    private void handleInject(ActionEvent e) {
        try {
            long pid = Long.parseLong(pidField.getText());
            String script = scriptArea.getText();
            Frida frida = new Frida(script, pid);
            if (!isRepetition) {
                try {
                    frida.run(() -> {
                    }).execute(frida1 -> frida1.addCallbackMessage(message ->
                            SwingUtilities.invokeLater(() -> {
                                logger.info("[LOG] {}", message);
                                logArea.append("[LOG] " + message + "\n");
                            })
                    )).start();
                } catch (Exception ex) {
                    logger.error("Injection failure", ex);
                    throw new RuntimeException(ex);
                }
                isRepetition = true;
            } else {
                try {
                    frida.run(() -> {
                    }).execute(frida12 -> {
                    }).start();
                } catch (Exception ex) {
                    logger.error("Injection failure", ex);
                }
            }

        } catch (NumberFormatException ex) {
            logger.error("无效的进程ID", ex);
            JOptionPane.showMessageDialog(this, "无效的进程ID", "错误", JOptionPane.ERROR_MESSAGE);
        }
    }

    private void openProcessSelectionWindow(ActionEvent e) {
        ProcessSelectionWindow selectionWindow = new ProcessSelectionWindow(this);
        selectionWindow.setVisible(true);
    }

    private static class ProcessSelectionWindow extends JDialog {
        private List<ProcessInfo> processList;
        private JTable table;

        public ProcessSelectionWindow(Window owner) {
            super(owner, language.getText("fridaWindow.processSelectionWindow"), ModalityType.APPLICATION_MODAL);
            setSize(600, 400);
            setLocationRelativeTo(owner);
            initializeUI();
        }

        private void initializeUI() {
            JPanel panel = new JPanel(new BorderLayout(5, 5));
            panel.setBorder(new EmptyBorder(10, 10, 10, 10));
            panel.setBackground(new Color(0x2B2B2B));

            JTextField searchField = new JTextField(20);
            styleSearchField(searchField);

            table = new JTable();
            table.setModel(createTableModel());
            styleTable(table);

            JScrollPane scrollPane = new JScrollPane(table);
            scrollPane.setBorder(BorderFactory.createLineBorder(new Color(0x3C3F41)));

            JPopupMenu contextMenu = createContextMenu();
            table.addMouseListener(new MouseAdapter() {
                public void mouseClicked(MouseEvent e) {
                    if (SwingUtilities.isRightMouseButton(e)) {
                        contextMenu.show(table, e.getX(), e.getY());
                    } else if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) {
                        injectSelectedProcess();
                    }
                }
            });

            panel.add(searchField, BorderLayout.NORTH);
            panel.add(scrollPane, BorderLayout.CENTER);
            setContentPane(panel);
        }

        private DefaultTableModel createTableModel() {
            processList = getProcesses();
            String[] columns = {"进程名称", "进程ID"};
            Object[][] data = getTableData(processList);
            return new DefaultTableModel(data, columns) {
                @Override
                public boolean isCellEditable(int row, int column) {
                    return false;
                }
            };
        }

        private void injectSelectedProcess() {
            int selectedRow = table.getSelectedRow();
            if (selectedRow != -1) {
                long pid = (Long) table.getModel().getValueAt(selectedRow, 1);
                ((FridaWindow) getOwner()).pidField.setText(String.valueOf(pid));
                dispose();
            }
        }

        private void styleSearchField(JTextField field) {
            field.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12));
            field.putClientProperty("JTextField.placeholderText", "输入进程名搜索...");
            field.setBorder(BorderFactory.createCompoundBorder(
                    BorderFactory.createLineBorder(new Color(0x515658)),
                    BorderFactory.createEmptyBorder(5, 8, 5, 8)
            ));
        }

        private void styleTable(JTable table) {
            table.setRowHeight(28);
            table.setIntercellSpacing(new Dimension(0, 0));
            table.setShowGrid(false);
            table.setSelectionBackground(new Color(0x214283));

            // 自定义渲染器
            table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
                @Override
                public Component getTableCellRendererComponent(JTable table, Object value,
                                                               boolean isSelected, boolean hasFocus, int row, int column) {
                    Component c = super.getTableCellRendererComponent(table, value,
                            isSelected, hasFocus, row, column);
                    c.setBackground(row % 2 == 0 ? new Color(0x323232) : new Color(0x2B2B2B));
                    c.setForeground(Color.WHITE);
                    return c;
                }
            });
        }

        private JPopupMenu createContextMenu() {
            JPopupMenu menu = new JPopupMenu();
            JMenuItem injectItem = new JMenuItem("注入选中进程");
            injectItem.addActionListener(e -> injectSelectedProcess());
            menu.add(injectItem);
            return menu;
        }

        private Object[][] getTableData(List<ProcessInfo> processes) {
            Object[][] data = new Object[processes.size()][2];
            for (int i = 0; i < processes.size(); i++) {
                ProcessInfo process = processes.get(i);
                data[i] = new Object[]{process.name(), process.pid()};
            }
            return data;
        }

        /**
         * 执行cmd命令获取所有进程信息
         *
         * @return 进程信息列表
         */
        private List<ProcessInfo> getProcesses() {
            List<ProcessInfo> processList = new ArrayList<>();
            try {
                Process process = Runtime.getRuntime().exec("tasklist /fo csv /nh");
                BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                String line;

                while ((line = reader.readLine()) != null) {
                    String[] columns = line.split(",");
                    if (columns.length > 1) {
                        long pid = Long.parseLong(columns[1].replaceAll("\"", "").trim());
                        String processName = columns[0].replaceAll("\"", "").trim();
                        processList.add(new ProcessInfo(pid, processName));
                    }
                }
                reader.close();
            } catch (IOException e) {
                logger.error("Failed to get process information ", e);
            }
            return processList;
        }
    }

    private record ProcessInfo(long pid, String name) {
    }

    public static void main(String[] args) {

    }
}
