package com.sencorsta.rabs.ui.robot;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import com.sencorsta.rabs.util.ClipboardWriter;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.GDI32;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinGDI;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.Point;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MouseInfo;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

/**
 * @author daibin
 */
public class OnePunchPanel extends JPanel {

    private String selectedWindowTitle;
    JComboBox<String> windowComboBox = new JComboBox<>();
    JButton captureButton = new JButton("Capture Window");
    JButton checkButton = new JButton("check");
    JButton writeButton = new JButton("write");
    private JPanel screenshotPanel = new JPanel();
    private JLabel screenshotLabel = new JLabel();
    private BufferedImage screenCapture;
    static ImageIcon find = new ImageIcon(ClassLoader.getSystemClassLoader().getResource("find.png").getPath());
    static ImageIcon find2 = new ImageIcon(ClassLoader.getSystemClassLoader().getResource("find2.png").getPath());
    private Rectangle windowRect;

    private JTextField regexTextField = new JTextField();

    public OnePunchPanel() {
        setLayout(new BorderLayout());

        JPanel controlPanel = new JPanel(new FlowLayout());
        controlPanel.add(regexTextField);
        controlPanel.add(windowComboBox);
        controlPanel.add(captureButton);
        controlPanel.add(checkButton);
        controlPanel.add(writeButton);

        add(controlPanel, BorderLayout.NORTH);

        // Set up a border for the screenshotPanel
        Border border = BorderFactory.createLineBorder(Color.BLACK, 2);
        screenshotPanel.setBorder(border);

        // Add the screenshotLabel to the screenshotPanel
        screenshotPanel.add(screenshotLabel);

        add(screenshotPanel, BorderLayout.CENTER);

        getWindowTitles();

        regexTextField.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                System.out.println("e = " + e);
                getWindowTitles();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                System.out.println("e = " + e);
                getWindowTitles();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                System.out.println("e = " + e);
                getWindowTitles();
            }
        });

        captureButton.addActionListener(e -> {
            selectedWindowTitle = (String) windowComboBox.getSelectedItem();
            if (selectedWindowTitle != null) {
                try {
                    captureWindow(selectedWindowTitle);
                } catch (AWTException awtException) {
                    awtException.printStackTrace();
                }
            }
        });
        checkButton.addActionListener(e -> {
            try {
                captureWindow(selectedWindowTitle);
            } catch (AWTException awtException) {
                awtException.printStackTrace();
            }
            // 使用 OpenCV 进行模板匹配
            Mat template = Imgcodecs.imread(System.getProperty("user.dir") + "\\opencv\\template\\find.png");
            Mat image = bufferedImageToMat(screenCapture);

            Mat result = new Mat();
            Imgproc.matchTemplate(image, template, result, Imgproc.TM_CCOEFF_NORMED);

            Core.MinMaxLocResult mmr = Core.minMaxLoc(result);
            double maxCorrelation = mmr.maxVal;
            Point matchLoc = mmr.maxLoc; // 获取匹配区域的左上角坐标
            // 根据需要设置相似度的阈值
            double similarityThreshold = 0.8048875331878662;
            System.out.println("maxCorrelation = " + maxCorrelation);
            if (maxCorrelation >= similarityThreshold) {
                System.out.println("图像包含相似内容。");
                System.out.println("匹配区域左上角坐标: (" + matchLoc.x + ", " + matchLoc.y + ")");
                // 创建 Robot 对象
                Robot robot = null;
                try {
                    robot = new Robot();
                } catch (AWTException awtException) {
                    awtException.printStackTrace();
                }

                java.awt.Point currentMouseLocation = MouseInfo.getPointerInfo().getLocation();
                int currentMouseX = currentMouseLocation.x;
                int currentMouseY = currentMouseLocation.y;
                // 将鼠标移动到匹配区域的左上角坐标
                robot.mouseMove(this.windowRect.x + (int) matchLoc.x + template.cols() / 2, this.windowRect.y + (int) matchLoc.y + template.rows() / 2);

                // 执行鼠标左键单击操作
                robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
                robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
                robot.mouseMove(currentMouseX, currentMouseY);
            } else {
                System.out.println("图像不包含相似内容。");
            }
        });
        writeButton.addActionListener(e -> {
            try {
                captureWindow(selectedWindowTitle);
            } catch (AWTException awtException) {
                awtException.printStackTrace();
            }

            Mat template = Imgcodecs.imread("C:\\Users\\daibin\\Desktop\\rabs\\src\\main\\resources\\find2.png");
            Mat image = bufferedImageToMat(screenCapture);

            Mat result = new Mat();
            Imgproc.matchTemplate(image, template, result, Imgproc.TM_CCOEFF_NORMED);

            Core.MinMaxLocResult mmr = Core.minMaxLoc(result);
            double maxCorrelation = mmr.maxVal;
            Point matchLoc = mmr.maxLoc; // 获取匹配区域的左上角坐标
            // 根据需要设置相似度的阈值
            double similarityThreshold = 0.9;

            if (maxCorrelation >= similarityThreshold) {
                System.out.println("图像包含相似内容。");
                System.out.println("匹配区域左上角坐标: (" + matchLoc.x + ", " + matchLoc.y + ")");
                // 创建 Robot 对象
                Robot robot = null;
                try {
                    robot = new Robot();
                } catch (AWTException awtException) {
                    awtException.printStackTrace();
                }
                // 获取当前鼠标坐标
                java.awt.Point currentMouseLocation = MouseInfo.getPointerInfo().getLocation();
                int currentMouseX = currentMouseLocation.x;
                int currentMouseY = currentMouseLocation.y;
                // 将鼠标移动到匹配区域的左上角坐标
                robot.mouseMove(this.windowRect.x + (int) matchLoc.x + 50, this.windowRect.y + (int) matchLoc.y + 100);

                // 执行鼠标左键单击操作
                robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
                robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);

                ClipboardWriter.writeToClipboard(result.toString());
                robot.delay(200);
                robot.keyPress(KeyEvent.VK_CONTROL);
                robot.keyPress(KeyEvent.VK_V);
                robot.keyRelease(KeyEvent.VK_V);
                robot.keyRelease(KeyEvent.VK_CONTROL);

                robot.mouseMove(currentMouseX, currentMouseY);
            } else {
                System.out.println("图像不包含相似内容。");
            }
        });



    }



    private void getWindowTitles() {
        windowComboBox.removeAllItems();
        final User32 user32 = User32.INSTANCE;
        user32.EnumWindows((hwnd, pointer) -> {
            char[] buffer = new char[1024];
            user32.GetWindowText(hwnd, buffer, buffer.length);
            String trim = new String(buffer).trim();
            if (StrUtil.isNotBlank(trim)) {
                if (isCommentMatched(trim, regexTextField.getText())) {
                    windowComboBox.addItem(trim);
                }
//                windowComboBox.addItem(trim);
            }
            return true;
        }, null);
    }

    public boolean isValidRegex(String regex) {
        try {
            Pattern.compile(regex);
            return true;
        } catch (PatternSyntaxException e) {
            return false;
        }
    }

    public boolean isCommentMatched(String comment, String searchText) {
        // 检查输入的 searchText 是否是合法的正则表达式
        if (!isValidRegex(searchText)) {
            return false;
        }
        // 将 searchText 编译为正则表达式
        Pattern pattern = Pattern.compile(searchText, Pattern.CASE_INSENSITIVE);
        // 创建 Matcher 对象，使用 comment 进行匹配
        Matcher matcher = pattern.matcher(comment);
        // 查找输入中是否存在与正则表达式匹配的文本
        return matcher.find();
    }

    private void captureWindow(String windowTitle) throws AWTException {
        User32 user32 = User32.INSTANCE;

        // Find the window by title
        WinDef.HWND windowHandle = user32.FindWindow(null, windowTitle);

        if (windowHandle == null) {
            System.out.println("Window not found: " + windowTitle);
            return;
        }
        User32.INSTANCE.ShowWindow(windowHandle, 9);        // SW_RESTORE
        User32.INSTANCE.SetForegroundWindow(windowHandle);   // bring to front
        ThreadUtil.sleep(200);
        this.windowRect = getWindowRect(windowHandle);


        screenCapture = new Robot().createScreenCapture(windowRect);
        ImageIcon originalImageIcon = new ImageIcon(screenCapture);

// 获取图像
        Image originalImage = originalImageIcon.getImage();

// 获取标签的大小
        int labelWidth = getWidth() - 20;
        int labelHeight = getHeight() - 50;

// 获取原始图像的大小
        int originalWidth = originalImageIcon.getIconWidth();
        int originalHeight = originalImageIcon.getIconHeight();

// 计算宽高比例
        double widthRatio = (double) labelWidth / originalWidth;
        double heightRatio = (double) labelHeight / originalHeight;

// 计算缩放比例，选择较小的比例以保持高宽比
        double scaleRatio = Math.min(widthRatio, heightRatio);

// 计算缩放后的宽度和高度
        int scaledWidth = (int) (originalWidth * scaleRatio);
        int scaledHeight = (int) (originalHeight * scaleRatio);

// 缩放图像以适应标签
        Image scaledImage = originalImage.getScaledInstance(scaledWidth, scaledHeight, Image.SCALE_SMOOTH);

// 创建新的 ImageIcon
        ImageIcon scaledImageIcon = new ImageIcon(scaledImage);

// 设置标签的图标
        screenshotLabel.setIcon(scaledImageIcon);

        screenshotLabel.repaint();
    }

    private Rectangle getWindowRect(WinDef.HWND windowHandle) {
        WinDef.RECT rect = new WinDef.RECT();
        User32.INSTANCE.GetWindowRect(windowHandle, rect);
        return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
    }

    private BufferedImage captureScreen(WinDef.HWND hwnd, Rectangle region) {
        int width = region.width;
        int height = region.height;

        WinDef.HDC hdc = User32.INSTANCE.GetDC(hwnd);
        WinDef.HDC hdcMem = GDI32.INSTANCE.CreateCompatibleDC(hdc);

        WinDef.HBITMAP hBitmap = GDI32.INSTANCE.CreateCompatibleBitmap(hdc, width, height);

        WinGDI.BITMAPINFO bmi = new WinGDI.BITMAPINFO();
        bmi.bmiHeader.biWidth = width;
        bmi.bmiHeader.biHeight = -height;
        bmi.bmiHeader.biPlanes = 1;
        bmi.bmiHeader.biBitCount = 32;
        bmi.bmiHeader.biCompression = WinGDI.BI_RGB;
        GDI32.INSTANCE.SelectObject(hdcMem, hBitmap);
        GDI32.INSTANCE.BitBlt(hdcMem, 0, 0, width, height, hdc, region.x, region.y, GDI32.SRCCOPY);
        long imageSize = ((long) Math.abs(bmi.bmiHeader.biHeight)) * bmi.bmiHeader.biWidth * (bmi.bmiHeader.biBitCount / 8);
        Pointer bits = new Memory(imageSize);
        GDI32.INSTANCE.GetDIBits(hdcMem, hBitmap, 0, height, bits, bmi, WinGDI.DIB_RGB_COLORS);

        int[] pixels = bits.getIntArray(0, width * height);
        if (isAllZero(pixels)) {
            System.out.println("pixels 内容为空 size = " + pixels.length);
        }
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        image.setRGB(0, 0, width, height, pixels, 0, width);


        GDI32.INSTANCE.DeleteDC(hdcMem);
        GDI32.INSTANCE.DeleteObject(hBitmap);
        User32.INSTANCE.ReleaseDC(hwnd, hdc);

        return image;
    }

    public static boolean isAllZero(int... args) {
        for (int obj : args) {
            if (1 == obj) {
                return false;
            }
        }
        return true;
    }

    public static Mat bufferedImageToMat(BufferedImage bufferedImage) {
        try {
            // Convert BufferedImage to byte array
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ImageIO.write(bufferedImage, "png", byteArrayOutputStream);
            byte[] imageBytes = byteArrayOutputStream.toByteArray();

            // Convert byte array to Mat
            MatOfByte matOfByte = new MatOfByte(imageBytes);
            Mat mat = Imgcodecs.imdecode(matOfByte, Imgcodecs.IMREAD_UNCHANGED);

            return mat;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static Mat imageIconToMat(ImageIcon imageIcon) {
        // Convert ImageIcon to BufferedImage
        BufferedImage bufferedImage = new BufferedImage(
                imageIcon.getIconWidth(),
                imageIcon.getIconHeight(),
                BufferedImage.TYPE_INT_RGB
        );
        Graphics g = bufferedImage.createGraphics();
        imageIcon.paintIcon(null, g, 0, 0);
        g.dispose();

        // Convert BufferedImage to Mat
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ImageIO.write(bufferedImage, "png", byteArrayOutputStream);
            byte[] imageBytes = byteArrayOutputStream.toByteArray();

            MatOfByte matOfByte = new MatOfByte(imageBytes);
            Mat mat = Imgcodecs.imdecode(matOfByte, Imgcodecs.IMREAD_UNCHANGED);

            return mat;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }


}
