package com.axis.innovators.box.gui;

import com.axis.innovators.box.events.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.swing.*;
import javax.swing.Timer;
import javax.swing.plaf.PanelUI;
import javax.swing.plaf.basic.BasicScrollBarUI;
import javax.swing.plaf.basic.BasicTabbedPaneUI;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
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;

    public MainWindow() {
        setIconImage(LoadIcon.loadIcon("logo.png", 32).getImage());
    }

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

    public void initUI() {
        setTitle("轴创工具箱 v1.0");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(1200, 800);
        setLocationRelativeTo(null);

        JPanel mainPanel = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g;
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                Color color1 = new Color(235, 241, 250);
                Color color2 = new Color(255, 255, 255);
                GradientPaint gp = new GradientPaint(0, 0, color1, getWidth(), getHeight(), color2);
                g2d.setPaint(gp);
                g2d.fillRect(0, 0, getWidth(), getHeight());

                if (isBackground) {
                    try {
                        ImageIcon backgroundImage = LoadIcon.loadIcon("start_page.png", 500);
                        if (isBlur) {
                            BufferedImage bufferedImage = toBufferedImage(backgroundImage.getImage());
                            BufferedImage blurredImage = applyGaussianBlur(bufferedImage, 5);
                            g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.1f));
                            int x = (getWidth() - blurredImage.getWidth()) / 2;
                            int y = (getHeight() - blurredImage.getHeight()) / 2;
                            g2d.drawImage(blurredImage, x, y, this);
                        } else {
                            int x = (getWidth() - backgroundImage.getIconWidth()) / 2;
                            int y = (getHeight() - backgroundImage.getIconHeight()) / 2;
                            g2d.drawImage(backgroundImage.getImage(), x, y, this);
                        }

                        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
                    } catch (Exception e) {
                        logger.error("Failed to load background image", e);
                    }
                }
            }
        };

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

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

        GlobalEventBus.EVENT_BUS.post(new MainWindowEvents.initialize(this, mainPanel));

        add(mainPanel);
    }

    private BufferedImage toBufferedImage(Image img) {
        if (img instanceof BufferedImage) {
            return (BufferedImage) img;
        }
        BufferedImage bimage = new BufferedImage(
                img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
        Graphics2D bGr = bimage.createGraphics();
        bGr.drawImage(img, 0, 0, null);
        bGr.dispose();
        return bimage;
    }

    /**
     * 对图像应用动感模糊效果。
     *
     * @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.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));

            tabbedPane.addTab(
                    category.getName(),
                    LoadIcon.loadIcon(category.getIcon(),  24),
                    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("轴创工具箱");
        title.setFont(new Font("微软雅黑", Font.BOLD, 28));
        title.setForeground(new Color(44, 62, 80));

        //JLabel iconLabel = new JLabel(LoadIcon.loadIcon("logo.png", 28));
        //iconLabel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));

        JButton settings = new JButton(LoadIcon.loadIcon("settings.png", 32));
        settings.setContentAreaFilled(false);
        settings.addActionListener(e -> showSettings());

        JPanel titlePanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
        titlePanel.setOpaque(false);
        //titlePanel.add(iconLabel);
        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 void showSettings() {
        JDialog dialog = new JDialog(this, "系统设置", true);
        dialog.setSize(600, 400);
        dialog.setLocationRelativeTo(this);

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

        GlobalEventBus.EVENT_BUS.post(new SettingsLoadEvents(dialog, content));

        dialog.add(content);
        dialog.setVisible(true);
    }



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

                // 绘制阴影
                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.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 = new JLabel(LoadIcon.loadIcon(tool.icon(), 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.title());
        titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 18));
        titleLabel.setForeground(new Color(44, 62, 80));
        titleLabel.setAlignmentX(Component.CENTER_ALIGNMENT);

        JTextArea descArea = new JTextArea(tool.description());
        descArea.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        descArea.setForeground(new Color(127, 140, 153));
        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);
            }
        });
        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.description() + "</p>" +
                "</body></html>";
    }

    // 工具类别内部类
    public static class ToolCategory {
        private final String name;
        private final String icon;
        private final String description;
        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;
        }

        /**
         * 注册工具的方法
         * @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;
        }
    }

    // 工具项数据类

    /**
     * 工具注册类
     * @param title 工具的标题（显示名称）
     * @param icon 工具的图标（resources的路径）
     * @param description 工具的描述
     * @param id 工具的id（请不要重复注册相同id的工具）
     * @param action 工具的点击事件
     */
    public record ToolItem(String title, String icon, String description, int id, Action action) {

        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;

        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) {
            startReleaseAnimation(() -> tool.action().actionPerformed(
                    new ActionEvent(card, ActionEvent.ACTION_PERFORMED, "")
            ));
        }

        @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 paintTrack(Graphics g, JComponent c, Rectangle trackBounds) {
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,  RenderingHints.VALUE_ANTIALIAS_ON);

            // 设置轨道背景颜色
            Color trackColor = new Color(240, 240, 240);
            g2d.setColor(trackColor);
            g2d.fillRoundRect(
                    trackBounds.x,
                    trackBounds.y,
                    trackBounds.width  - 1,
                    trackBounds.height  - 1,
                    5, 5 // 圆角半径
            );
        }

        @Override
        protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) {
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,  RenderingHints.VALUE_ANTIALIAS_ON);

            Color thumbColor = new Color(180, 180, 180);
            g2d.setColor(thumbColor);
            g2d.fillRoundRect(
                    thumbBounds.x,
                    thumbBounds.y,
                    thumbBounds.width  - 1,
                    thumbBounds.height  - 1,
                    5, 5
            );

            Color borderColor = new Color(160, 160, 160);
            g2d.setColor(borderColor);
            g2d.drawRoundRect(
                    thumbBounds.x,
                    thumbBounds.y,
                    thumbBounds.width  - 1,
                    thumbBounds.height  - 1,
                    5, 5
            );
        }

        @Override
        protected void paintDecreaseHighlight(Graphics g) {}

        @Override
        protected void paintIncreaseHighlight(Graphics g) {}
    }
}