package com.axis.innovators.box.gui;

import com.axis.innovators.box.AxisInnovatorsBox;
import com.axis.innovators.box.decompilation.gui.ModernJarViewer;
import com.axis.innovators.box.events.*;
import com.axis.innovators.box.register.RegistrationSettingsItem;
import com.axis.innovators.box.register.LanguageManager;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.swing.*;
import javax.swing.Timer;
import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.PanelUI;
import javax.swing.plaf.basic.BasicScrollBarUI;
import javax.swing.plaf.basic.BasicTabbedPaneUI;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.util.*;
import java.util.List;

/**
 * 显示窗口（显示的主窗口）
 * @author tzdwindows 7
 */
public class MainWindow extends JFrame {
    private static final Logger logger = LogManager.getLogger(MainWindow.class);
    private final Map<JComponent, Float> cardScales = new HashMap<>();
    private final Map<JComponent, Integer> cardElevations = new HashMap<>();
    private final Color CARD_COLOR = Color.WHITE;
    private final List<ToolCategory> categories = new ArrayList<>();
    private final boolean isBackground = true;
    private final boolean isBlur = true;
    private SystemTray systemTray;
    private TrayIcon trayIcon;

    public MainWindow() {
        setIconImage(LoadIcon.loadIcon("logo.png", 32).getImage());
        addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                for (JComponent card : cardScales.keySet()) {
                    cardScales.put(card, 1.0f);
                    card.repaint();
                }
            }
        });
    }

    /**
     * 添加工具分类
     * @param category 工具分类
     */
    public void addToolCategory(ToolCategory category){
        categories.add(category);
    }


    public void initUI() {
        setTitle(LanguageManager.getLoadedLanguages().getText("mainWindow.title"));
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(1200, 800);
        setLocationRelativeTo(null);

        setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);

        getContentPane().setBackground(new Color(0, 0, 0, 0));

        JPanel mainPanel = new JPanel();

        mainPanel.setOpaque(true);

        mainPanel.setLayout(new BorderLayout(20, 20));
        mainPanel.setBorder(BorderFactory.createEmptyBorder(30, 30, 30, 30));

        mainPanel.add(createHeader(), BorderLayout.NORTH);
        mainPanel.add(createCategoryTabs(), BorderLayout.CENTER);

        add(mainPanel);
        createSystemTray();
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                setVisible(false);
            }
        });
    }

    private void createSystemTray() {
        if (!SystemTray.isSupported()) {
            logger.error("系统托盘不支持！");
            return;
        }

        // 初始化系统托盘
        systemTray = SystemTray.getSystemTray();

        // 1. 加载并处理圆角图标（修正图像类型）
        ImageIcon rawIcon = LoadIcon.loadIcon("logo.png", 64);
        Image roundedImage = createRoundedIcon(rawIcon.getImage(), 16);

        // 2. 创建支持中文的弹出菜单
        PopupMenu popup = new PopupMenu();

        // 3. 创建菜单项（使用标准AWT组件）
        MenuItem openItem = createBaseMenuItem("打开主界面", e -> setVisible(true));
        MenuItem decompileItem = createBaseMenuItem("打开反编译工具", e ->
                new ModernJarViewer(null).setVisible(true));
        MenuItem exitItem = createBaseMenuItem("退出程序", e -> AxisInnovatorsBox.getMain().quit());

        // 4. 构建菜单结构
        popup.add(openItem);
        popup.addSeparator();
        popup.add(decompileItem);
        popup.addSeparator();
        popup.add(exitItem);

        // 5. 创建托盘图标
        trayIcon = new TrayIcon(roundedImage, "轴创工具箱", popup);
        trayIcon.setImageAutoSize(true);

        // 6. 添加事件监听
        addTrayEventListeners();

        try {
            systemTray.add(trayIcon);
        } catch (AWTException ex) {
            logger.error("添加系统托盘图标失败", ex);
        }
    }

    // 基础菜单项创建方法（解决方法不存在问题）
    private MenuItem createBaseMenuItem(String text, ActionListener action) {
        MenuItem item = new MenuItem(text);
        item.addActionListener(action);
        return item;
    }

    // 圆角图标生成（修正版）
    private Image createRoundedIcon(Image source, int cornerRadius) {
        int size = Math.max(source.getWidth(null), source.getHeight(null));
        BufferedImage output = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);

        Graphics2D g2 = output.createGraphics();
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // 创建剪切路径
        RoundRectangle2D roundRect = new RoundRectangle2D.Float(0, 0, size, size, cornerRadius, cornerRadius);
        g2.setClip(roundRect);
        g2.drawImage(source, 0, 0, size, size, null);

        g2.dispose();
        return output;
    }

    // 添加事件监听
    private void addTrayEventListeners() {
        // 双击恢复窗口
        trayIcon.addActionListener(e -> setVisible(true));

        // 右键菜单触发兼容处理
        trayIcon.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    trayIcon.getPopupMenu().show(e.getComponent(), e.getX(), e.getY());
                }
            }
        });
    }

    // 初始化中文字体（在main方法或构造函数中调用）
    private void initChineseFont() {
        String[] fontPriority = {
                "Microsoft YaHei",
                "PingFang SC",
                "SimSun",
                Font.DIALOG
        };

        for (String fontName : fontPriority) {
            if (isFontAvailable(fontName)) {
                setGlobalFont(new Font(fontName, Font.PLAIN, 12));
                break;
            }
        }
    }

    // 字体可用性检查
    private boolean isFontAvailable(String fontName) {
        return Arrays.asList(GraphicsEnvironment
                        .getLocalGraphicsEnvironment()
                        .getAvailableFontFamilyNames())
                .contains(fontName);
    }

    // 全局字体设置
    private void setGlobalFont(Font font) {
        FontUIResource fontRes = new FontUIResource(font);
        UIManager.put("MenuItem.font", fontRes);
        UIManager.put("Menu.font", fontRes);
    }

    /**
     * 对图像应用动感模糊效果。
     *
     * @param srcImage 需要应用动感模糊的源图像。
     *                 这个参数应该是一个 `BufferedImage` 类型的对象。
     * @param radius   动感模糊的半径，决定模糊效果的范围。
     *                 半径越大，模糊范围越广，模糊效果越强。
     * @param angle    动感模糊的角度，决定模糊效果的方向。
     *                 角度单位为度，表示从正Y轴顺时针的旋转角度。
     *                 比如：
     *                 - `0` 表示水平方向的模糊。
     *                 - `90` 表示垂直方向的模糊。
     *                 - 其他角度则表示不同方向的模糊。
     * @return 返回应用了动感模糊效果的 `BufferedImage` 图像。
     *         原始图像不会被修改，返回的是处理过的新图像。
     */
    public BufferedImage applyMotionBlur(BufferedImage srcImage, int radius, int angle) {
        double radian = Math.toRadians(angle);

        float[] matrix = new float[radius * radius];
        float sum = 0.0f;
        int index = 0;

        for (int y = -radius / 2; y <= radius / 2; y++) {
            for (int x = -radius / 2; x <= radius / 2; x++) {
                float weight = (float) (Math.cos(radian) * x + Math.sin(radian) * y);
                if (Math.abs(weight) < 1) {
                    matrix[index++] = 1.0f;
                    sum += 1.0f;
                } else {
                    matrix[index++] = 0.0f;
                }
            }
        }

        return getBufferedImage(srcImage, radius, matrix, sum);
    }

    private BufferedImage getBufferedImage(BufferedImage srcImage, int radius, float[] matrix, float sum) {
        for (int i = 0; i < matrix.length; i++) {
            matrix[i] /= sum;
        }
        Kernel kernel = new Kernel(radius, radius, matrix);
        ConvolveOp convolve = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
        return convolve.filter(srcImage, null);
    }

    /**
     * 应用高斯模糊效果到给定的图像。
     *
     * @param srcImage 输入的原始图像，类型为 `BufferedImage`。
     * @param radius 高斯模糊的半径，表示模糊的强度。半径越大，模糊效果越强。
     * @return 返回模糊处理后的图像，类型为 `BufferedImage`。
     */
    public BufferedImage applyGaussianBlur(BufferedImage srcImage, int radius) {
        if (radius > 100) {
            radius = 100;
        }

        float[] matrix = new float[radius * radius];
        float sigma = radius / 2f;
        float sum = 0.0f;
        int index = 0;

        for (int y = -radius / 2; y <= radius / 2; y++) {
            for (int x = -radius / 2; x <= radius / 2; x++) {
                float weight = (float) Math.exp(-(x * x + y * y) / (2 * sigma * sigma));
                matrix[index] = weight;
                index++;
                sum += weight;
            }
        }

        return getBufferedImage(srcImage, radius, matrix, sum);
    }

    private JComponent createCategoryTabs() {
        JTabbedPane tabbedPane = new JTabbedPane();

        //tabbedPane.putClientProperty(FlatClientProperties.TABBED_PANE_TAB_AREA_ALIGN, Component.LEFT_ALIGNMENT);
        tabbedPane.putClientProperty(FlatClientProperties.TABBED_PANE_TAB_HEIGHT, 40);
        tabbedPane.putClientProperty(FlatClientProperties.TABBED_PANE_TAB_ICON_PLACEMENT, SwingConstants.TOP);

        tabbedPane.setOpaque(false);
        tabbedPane.setBackground(new  Color(0, 0, 0, 0));
        tabbedPane.setBorder(null);

        //tabbedPane.setUI(new  CustomTabbedPaneUI());

        for (ToolCategory category : categories) {
            JPanel toolsPanel = createToolsPanel(category);
            toolsPanel.setOpaque(false);
            toolsPanel.setBorder(null);

            JScrollPane scrollPane = new JScrollPane(toolsPanel);
            scrollPane.setBorder(null);
            scrollPane.setOpaque(false);
            scrollPane.getViewport().setOpaque(false);
            JScrollBar verticalScrollBar = scrollPane.getVerticalScrollBar();
            //verticalScrollBar.setUI(new  CustomScrollBarUI());
            verticalScrollBar.setPreferredSize(new  Dimension(10, 100));

            if (category.getIcon() == null){
                tabbedPane.addTab(
                        category.getName(),
                        category.getIconImage(),
                        scrollPane
                );
            }
            tabbedPane.addTab(
                    category.getName(),
                    LoadIcon.loadIcon(category.getIcon(),  12),
                    scrollPane
            );
        }

        return tabbedPane;
    }

    private JPanel createToolsPanel(ToolCategory category) {
        JPanel panel = new JPanel(new GridLayout(0, 3, 20, 20));
        for (ToolItem tool : category.getTools()) {
            panel.add(createToolCard(tool));
        }
        panel.setOpaque(false);
        panel.setBorder(null);
        return panel;
    }

    private JPanel createHeader() {
        JPanel header = new JPanel(new BorderLayout());
        header.setOpaque(false);
        header.setBorder(BorderFactory.createEmptyBorder(15, 30, 15, 30));

        // 创建标题
        JLabel title = new JLabel(LanguageManager.getLoadedLanguages().getText("mainWindow.title.2"));
        title.setFont(new Font("微软雅黑", Font.BOLD, 28));
        title.setForeground(new Color(255, 255, 255));

        JButton settings = new JButton(LoadIcon.loadIcon("settings.png", 32));
        settings.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_BORDERLESS);
        settings.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        settings.setContentAreaFilled(false);
        settings.addActionListener(e -> showSettings());

        JPanel titlePanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
        titlePanel.setOpaque(false);
        titlePanel.add(title);

        header.add(titlePanel, BorderLayout.WEST);
        header.add(settings, BorderLayout.EAST);

        return header;
    }


    @Override
    public void update(Graphics g) {
        GlobalEventBus.EVENT_BUS.post(new MainWindowEvents.update(this, g));
        super.update(g);
    }

    private WindowsJDialog dialog;
    public void showSettings() {
        if (dialog == null || !AxisInnovatorsBox.getMain().isWindowStartup(dialog)) {
            dialog = new WindowsJDialog(this,
                    LanguageManager.getLoadedLanguages().getText("mainWindow.settings.title"), true);
        }
        dialog.setTitle(LanguageManager.getLoadedLanguages().getText("mainWindow.settings.title"));
        dialog.setSize(600, 400);
        dialog.setLocationRelativeTo(this);

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

        JTabbedPane tabbedPane = new JTabbedPane();

        List<RegistrationSettingsItem> registrationSettingsItemList
                = RegistrationSettingsItem.getRegistrationSettingsItemList();
        for (RegistrationSettingsItem registrationSettingsItem : registrationSettingsItemList) {
            registrationSettingsItem.registration(tabbedPane);
        }

        content.add(tabbedPane, BorderLayout.CENTER);
        GlobalEventBus.EVENT_BUS.post(new SettingsLoadEvents(dialog, content));
        dialog.add(content);
        dialog.revalidate();
        if (!AxisInnovatorsBox.getMain().isWindowStartup(dialog)) {
            AxisInnovatorsBox.getMain().popupWindow(dialog);
        }
    }

    private JPanel createToolCard(ToolItem tool) {
        JPanel card = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                Graphics2D g2d = (Graphics2D) g.create();

                // 毛玻璃效果
                BufferedImage background = new BufferedImage(
                        getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
                super.paintComponent(background.getGraphics());
                BufferedImage blurred = applyGaussianBlur(background, 5);

                g2d.drawImage(blurred, 0, 0, null);

                // 绘制阴影
                int elevation = cardElevations.getOrDefault(this, 2);
                for (int i = 0; i < elevation; i++) {
                    g2d.setColor(new Color(0, 0, 0, 20 - i * 2));
                    g2d.fillRoundRect(i, i, getWidth() - i * 2, getHeight() - i * 2, 15, 15);
                }

                float scale = cardScales.getOrDefault(this, 1.0f);
                int offset = (int) ((scale - 1) * getWidth() / 2);
                g2d.translate(-offset, -offset);
                g2d.scale(scale, scale);

                super.paintComponent(g2d);
                g2d.dispose();
            }
        };
        card.setPreferredSize(new Dimension(200, 150));
        card.setMinimumSize(new Dimension(100, 75));
        card.setLayout(new BorderLayout(15, 15));
        //card.setBackground(CARD_COLOR);
        card.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createLineBorder(new Color(225, 229, 234), 1),
                BorderFactory.createEmptyBorder(20, 20, 20, 20)
        ));
        card.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        JLabel iconLabel;
        if (tool.getIcon() == null){
            iconLabel = new JLabel(tool.getImageIcon());
        }else {
            iconLabel = new JLabel(LoadIcon.loadIcon(tool.getIcon(), 64));
        }

        iconLabel.setHorizontalAlignment(SwingConstants.CENTER);

        // 文字面板
        JPanel textPanel = new JPanel();
        textPanel.setLayout(new BoxLayout(textPanel, BoxLayout.Y_AXIS));
        textPanel.setOpaque(false);

        JLabel titleLabel = new JLabel(tool.getTitle());
        titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 18));
        titleLabel.setForeground(new Color(255, 255, 255));
        titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT);

        JTextArea descArea = new JTextArea(tool.getDescription());
        descArea.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        descArea.setForeground(new Color(177, 177, 177));
        descArea.setLineWrap(true);
        descArea.setWrapStyleWord(true);
        descArea.setEditable(false);
        descArea.setOpaque(false);
        descArea.setAlignmentX(Component.CENTER_ALIGNMENT);

        card.setToolTipText(createToolTipHTML(tool));

        textPanel.add(titleLabel);
        textPanel.add(Box.createVerticalStrut(10));
        textPanel.add(descArea);

        card.add(iconLabel, BorderLayout.NORTH);
        card.add(textPanel, BorderLayout.CENTER);

        card.addMouseListener(new CardMouseAdapter(card, tool));
        card.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                SwingUtilities.invokeLater(() -> {

                });
            }
        });
        card.setUI(new PanelUI() {
            @Override
            public void installUI(JComponent c) {
                GlobalEventBus.EVENT_BUS.post(new TABUIEvents(card, c));
                super.installUI(c);
            }

            @Override
            public void update(Graphics g, JComponent c) {
                GlobalEventBus.EVENT_BUS.post(new TABUIEvents.update(g, c));
                super.update(g, c);
            }
        });

        card.addMouseListener(new CardMouseAdapter(card, tool) {
            @Override
            public void mouseEntered(MouseEvent e) {
                cardElevations.put(card, 8);
                animateCardElevation(card, 8);
            }

            @Override
            public void mouseExited(MouseEvent e) {
                animateCardElevation(card, 2);
            }
        });
        return card;
    }


    private String createToolTipHTML(ToolItem tool) {
        return "<html><body style='width: 300px; padding: 10px;'>" +
                "<h3 style='color: #2c3e50; margin: 0 0 8px 0;'>" + tool.getName() + "</h3>" +
                "<p style='color: #7f8c99; margin: 0;'>" + tool.getDescription() + "</p>" +
                "</body></html>";
    }

    private void animateCardElevation(JComponent card, int targetElevation) {
        new Timer(10, new AbstractAction() {
            private int currentElevation = cardElevations.getOrDefault(card, 2);

            @Override
            public void actionPerformed(ActionEvent e) {
                if (currentElevation < targetElevation) currentElevation++;
                else if (currentElevation > targetElevation) currentElevation--;

                cardElevations.put(card, currentElevation);
                card.repaint();

                if (currentElevation == targetElevation) {
                    ((Timer)e.getSource()).stop();
                }
            }
        }).start();
    }

    public static class ToolCategory {
        private final String name;
        private final String icon;
        private final ImageIcon iconImage;
        private final String description;
        private final UUID id = UUID.randomUUID();
        private final List<ToolItem> tools = new ArrayList<>();

        /**
         * 一个大的分类项类
         * @param name 分类项的显示名称
         * @param icon 分类项的图标（resources的路径）
         * @param description 分类项的描述
         */
        public ToolCategory(String name, String icon, String description) {
            this.name = name;
            this.icon = icon;
            this.description = description;
            this.iconImage = null;
        }

        public ToolCategory(String name, ImageIcon icon, String description) {
            this.name = name;
            this.iconImage = icon;
            this.description = description;
            this.icon = null;
        }

        /**
         * 注册工具的方法
         * @param tool 工具项
         */
        public void addTool(ToolItem tool) {
            tools.add(tool);
        }

        public String getDescription() {
            return description;
        }

        public String getIcon() {
            return icon;
        }

        public String getName() {
            return name;
        }

        public List<ToolItem> getTools() {
            return tools;
        }

        public ImageIcon getIconImage() {
            return iconImage;
        }

        public UUID getId() {
            return id;
        }
    }

    // 工具项数据类

    /**
     * 工具注册类
     */
    public static class ToolItem {
        private final ImageIcon imageIcon;
        private final String title;
        private final String icon;

        private final String description;
        private final int id;
        private final Action action;

        public ToolItem(String title, String icon, String description, int id, Action action){
            this.title = title;
            this.icon = icon;
            this.description = description;
            this.id = id;
            this.action = action;
            this.imageIcon = null;
        }

        public ToolItem(String title, ImageIcon icon, String description, int id, Action action) {
            this.title = title;
            this.imageIcon = icon;
            this.description = description;
            this.id = id;
            this.action = action;
            this.icon = null;
        }

        public String getTitle() {
            return title;
        }

        public ImageIcon icon() {
            return imageIcon;
        }

        public String getIcon() {
            return icon;
        }

        public Action getAction() {
            return action;
        }

        public ImageIcon getImageIcon() {
            return imageIcon;
        }

        public int getId() {
            return id;
        }

        public String getDescription() {
            return description;
        }

        public String getName() {
            return title;
        }
    }

    // 分类栏面卡
    public static class CustomTabbedPaneUI extends BasicTabbedPaneUI {
        private static final Color SELECTED_COLOR = new Color(183, 202, 221);
        private static final Color UNSELECTED_COLOR = new Color(125, 174, 237);


        @Override
        protected void paintTabBackground(Graphics g, int tabPlacement,
                                          int tabIndex, int x, int y, int w, int h,
                                          boolean isSelected) {
            CategoryRenderingEvent event = new CategoryRenderingEvent(this, g, tabPlacement, tabIndex, x, y, w, h, isSelected);
            GlobalEventBus.EVENT_BUS.post(event);
            if (event.isEnd()){
                return;
            }
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            if (isSelected) {
                g2d.setColor(SELECTED_COLOR);
            } else {
                g2d.setColor(UNSELECTED_COLOR);
            }

            g2d.fillRoundRect(x + 2, y + 2, w - 4, h - 4, 10, 10);
            g2d.dispose();
        }

        @Override
        protected void paintTabBorder(Graphics g, int tabPlacement,
                                      int tabIndex, int x, int y, int w, int h,
                                      boolean isSelected) {
            GlobalEventBus.EVENT_BUS.post(new CategoryRenderingEvent.paintTabBorder(this, g,
                    tabPlacement,
                    tabIndex, x, y, w, h, isSelected));
        }
    }

    private class CardMouseAdapter extends MouseAdapter {
        private final JPanel card;
        private final ToolItem tool;
        private Timer pressTimer;
        private Timer releaseTimer;
        private static int delay = 0;
        public CardMouseAdapter(JPanel card, ToolItem tool) {
            this.card = card;
            this.tool = tool;
        }

        @Override
        public void mousePressed(MouseEvent e) {
            startPressAnimation();
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            if (delay == 0) {
                delay++;
                startReleaseAnimation(() -> tool.getAction().actionPerformed(
                        new ActionEvent(card, ActionEvent.ACTION_PERFORMED, "")
                ));
            } else {
                delay--;
            }
        }

        @Override
        public void mouseExited(MouseEvent e) {
            if (pressTimer != null && pressTimer.isRunning()) {
                startReleaseAnimation(null);
            }
        }

        private void startPressAnimation() {
            if (pressTimer != null && pressTimer.isRunning()) {
                return;
            }

            pressTimer = new Timer(10, new AbstractAction() {
                private final long startTime = System.currentTimeMillis();

                @Override
                public void actionPerformed(ActionEvent e) {
                    float progress = Math.min(1.0f,
                            (System.currentTimeMillis() - startTime) / 150f);

                    // 使用二次缓动函数
                    float scale = 1.0f - 0.1f * (float) Math.pow(progress, 0.5);
                    cardScales.put(card, scale);
                    card.repaint();

                    if (progress >= 1.0f) {
                        ((Timer) e.getSource()).stop();
                    }
                }
            });
            pressTimer.start();
        }

        private void startReleaseAnimation(Runnable callback) {
            if (pressTimer != null) {
                pressTimer.stop();
            }
            if (releaseTimer != null && releaseTimer.isRunning()) {
                return;
            }

            final float startScale = cardScales.getOrDefault(card, 1.0f);
            releaseTimer = new Timer(10, new AbstractAction() {
                private final long startTime = System.currentTimeMillis();

                @Override
                public void actionPerformed(ActionEvent e) {
                    float progress = Math.min(1.0f,
                            (System.currentTimeMillis() - startTime) / 200f);

                    // 使用弹性缓动函数
                    float scale = startScale +
                            (1.0f - startScale) * (float) (1 - Math.pow(1 - progress, 3));
                    cardScales.put(card, scale);
                    card.repaint();

                    if (progress >= 1.0f) {
                        ((Timer) e.getSource()).stop();
                        if (callback != null) {
                            callback.run();
                        }
                    }
                }
            });
            releaseTimer.start();
        }
    }

    public static class CustomScrollBarUI extends BasicScrollBarUI {
        @Override
        protected void configureScrollBarColors() {
            this.thumbColor = new Color(90, 90, 120);
            this.trackColor = new Color(50, 50, 70);
        }

        @Override
        protected JButton createDecreaseButton(int orientation) {
            return createInvisibleButton();
        }

        @Override
        protected JButton createIncreaseButton(int orientation) {
            return createInvisibleButton();
        }

        private JButton createInvisibleButton() {
            JButton btn = new JButton();
            btn.setPreferredSize(new Dimension(0, 0));
            btn.setMinimumSize(new Dimension(0, 0));
            btn.setMaximumSize(new Dimension(0, 0));
            return btn;
        }

        @Override
        protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) {
            Graphics2D g2 = (Graphics2D)g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2.setColor(thumbColor);
            g2.fillRoundRect(
                    thumbBounds.x + 2,
                    thumbBounds.y + 2,
                    thumbBounds.width - 4,
                    thumbBounds.height - 4,
                    8, 8
            );
        }
    }
}