package dev.bytevibe.hyperpoint;

import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontPosture;
import javafx.scene.text.FontWeight;

/**
 * 绘图Canvas组件，用于渲染和交互所有可绘制对象
 */
public class DrawingCanvas extends Pane {
    // 缩放点的枚举
    enum ResizePoint {
        TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT, NONE
    }

    private Canvas canvas;
    private PageContent pageContent;
    private DrawableObject selectedObject;
    private double lastX, lastY;
    private Runnable onSelectionChanged;

    // 缩放点有关的属性
    private ResizePoint resizePoint = ResizePoint.NONE;
    // 缩放点大小
    private static final double HANDLE_SIZE = 8;

    public DrawingCanvas(PageContent pageContent) {
        this.pageContent = pageContent;
        this.canvas = new Canvas();

        getChildren().add(canvas);

        // 设置鼠标事件处理
        setOnMousePressed(this::handleMousePressed);
        setOnMouseDragged(this::handleMouseDragged);
        setOnMouseReleased(this::handleMouseReleased);


        setStyle("-fx-border-color: #e0e0e0; -fx-border-width: 1;");

        // 绑定Canvas大小到Pane大小
        widthProperty().addListener((obs, oldVal, newVal) -> {
            canvas.setWidth(newVal.doubleValue());
            redraw();
        });
        heightProperty().addListener((obs, oldVal, newVal) -> {
            canvas.setHeight(newVal.doubleValue());
            redraw();
        });

        // 初始绘制
        redraw();
    }

    /**
     * 鼠标按下事件处理
     */
    private void handleMousePressed(MouseEvent event) {
        lastX = event.getX();
        lastY = event.getY();

        // 如果已经有选中对象，先检查是否点击在调整点上
        if (selectedObject != null) {
            resizePoint = getResizePointAt(lastX, lastY, selectedObject);
            if (resizePoint != ResizePoint.NONE) {
                // 点击在调整点上，进入缩放模式
                return;
            }
        }

        // 重置缩放模式
        resizePoint = ResizePoint.NONE;

        // 查找被点击的对象
        DrawableObject clicked = pageContent.findObjectAt(lastX, lastY);

        if (clicked == null) {
            setSelectedObject(null);
        } else {
            setSelectedObject(clicked);
        }

        redraw();
    }

    /**
     * 获取点击位置对应的调整点
     */
    private ResizePoint getResizePointAt(double x, double y, DrawableObject obj) {
        double handleSize = HANDLE_SIZE;
        double objX = obj.getX();
        double objY = obj.getY();
        double objW = obj.getWidth();
        double objH = obj.getHeight();

        // 检查左上角
        if (x >= objX - handleSize && x <= objX + handleSize &&
            y >= objY - handleSize && y <= objY + handleSize) {
            return ResizePoint.TOP_LEFT;
        }
        // 检查右上角
        if (x >= objX + objW - handleSize && x <= objX + objW + handleSize &&
            y >= objY - handleSize && y <= objY + handleSize) {
            return ResizePoint.TOP_RIGHT;
        }
        // 检查左下角
        if (x >= objX - handleSize && x <= objX + handleSize &&
            y >= objY + objH - handleSize && y <= objY + objH + handleSize) {
            return ResizePoint.BOTTOM_LEFT;
        }
        // 检查右下角
        if (x >= objX + objW - handleSize && x <= objX + objW + handleSize &&
            y >= objY + objH - handleSize && y <= objY + objH + handleSize) {
            return ResizePoint.BOTTOM_RIGHT;
        }

        return ResizePoint.NONE;
    }

    /**
     * 鼠标拖动事件处理
     */
    private void handleMouseDragged(MouseEvent event) {
        if (selectedObject != null) {
            double dx = event.getX() - lastX;
            double dy = event.getY() - lastY;

            // 如果正在缩放
            if (resizePoint != ResizePoint.NONE) {
                resizeObject(selectedObject, dx, dy, resizePoint);
            } else {
                // 移动对象
                selectedObject.setX(selectedObject.getX() + dx);
                selectedObject.setY(selectedObject.getY() + dy);
            }

            lastX = event.getX();
            lastY = event.getY();

            redraw();
        }
    }

    /**
     * 缩放对象
     */
    private void resizeObject(DrawableObject obj, double dx, double dy, ResizePoint point) {
        // 最小尺寸限制
        final double MIN_SIZE = 20;

        switch (point) {
            case TOP_LEFT:
                // 从左上角缩放：x和y增加，width和height减少
                if (obj.getWidth() - dx >= MIN_SIZE && obj.getHeight() - dy >= MIN_SIZE) {
                    obj.setX(obj.getX() + dx);
                    obj.setY(obj.getY() + dy);
                    obj.setWidth(obj.getWidth() - dx);
                    obj.setHeight(obj.getHeight() - dy);
                }
                break;
            case TOP_RIGHT:
                // 从右上角缩放：y增加，width增加，height减少
                if (obj.getWidth() + dx >= MIN_SIZE && obj.getHeight() - dy >= MIN_SIZE) {
                    obj.setY(obj.getY() + dy);
                    obj.setWidth(obj.getWidth() + dx);
                    obj.setHeight(obj.getHeight() - dy);
                }
                break;
            case BOTTOM_LEFT:
                // 从左下角缩放：x增加，width减少，height增加
                if (obj.getWidth() - dx >= MIN_SIZE && obj.getHeight() + dy >= MIN_SIZE) {
                    obj.setX(obj.getX() + dx);
                    obj.setWidth(obj.getWidth() - dx);
                    obj.setHeight(obj.getHeight() + dy);
                }
                break;
            case BOTTOM_RIGHT:
                // 从右下角缩放：width和height增加
                if (obj.getWidth() + dx >= MIN_SIZE && obj.getHeight() + dy >= MIN_SIZE) {
                    obj.setWidth(obj.getWidth() + dx);
                    obj.setHeight(obj.getHeight() + dy);
                }
                break;
            default:
                break;
        }
    }


    /**
     * 鼠标释放事件处理
     */
    private void handleMouseReleased(MouseEvent event) {
        // 释放鼠标时，重置缩放模式
        resizePoint = ResizePoint.NONE;
    }

    /**
     * 添加可绘制对象
     */
    public void addObject(DrawableObject object) {
        pageContent.addObject(object);
        redraw();
    }

    /**
     * 移除可绘制对象
     */
    public void removeObject(DrawableObject object) {
        if (selectedObject == object) {
            selectedObject = null;
        }
        pageContent.removeObject(object);
        redraw();
    }

    /**
     * 设置选中的对象
     */
    public void setSelectedObject(DrawableObject object) {
        selectedObject = object;
        if (onSelectionChanged != null) {
            onSelectionChanged.run();
        }
    }

    /**
     * 获取选中的对象
     */
    public DrawableObject getSelectedObject() {
        return selectedObject;
    }

    /**
     * 设置选择变化回调
     */
    public void setOnSelectionChanged(Runnable callback) {
        this.onSelectionChanged = callback;
    }

    /**
     * 重新绘制画布
     */
    public void redraw() {
        GraphicsContext gc = canvas.getGraphicsContext2D();

        // 清除画布（白色背景）
        gc.setFill(Color.WHITE);
        gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());

        // 绘制边框
        gc.setStroke(Color.web("#cccccc"));
        gc.setLineWidth(1);
        gc.strokeRect(0, 0, canvas.getWidth(), canvas.getHeight());

        // 绘制所有对象
        for (DrawableObject obj : pageContent.getDrawableObjects()) {
            drawObject(gc, obj, obj == selectedObject);
        }
    }

    /**
     * 绘制单个对象
     */
    private void drawObject(GraphicsContext gc, DrawableObject obj, boolean selected) {
        if (obj instanceof TextObject) {
            drawTextObject(gc, (TextObject) obj, selected);
        } else if (obj instanceof ShapeObject) {
            drawShapeObject(gc, (ShapeObject) obj, selected);
        } else if (obj instanceof ImageObject) {
            drawImageObject(gc, (ImageObject) obj, selected);
        }
    }

    /**
     * 绘制文本对象
     */
    private void drawTextObject(GraphicsContext gc, TextObject textObj, boolean selected) {
        // 设置字体和风格
        Font font = createFont(textObj.getFontFamily(), textObj.getFontSize(), textObj.getFontStyle());
        gc.setFont(font);

        // 绘制背景
        gc.setFill(Color.WHITE);
        gc.fillRect(textObj.getX(), textObj.getY(), textObj.getWidth(), textObj.getHeight());
        gc.setStroke(Color.LIGHTGRAY);
        gc.strokeRect(textObj.getX(), textObj.getY(), textObj.getWidth(), textObj.getHeight());

        // 设置文字颜色
        gc.setFill(textObj.getTextColorAsColor());

        // 获取排版后的文本行并绘制
        double lineHeight = textObj.getFontSize() * 1.2;
        double currentY = textObj.getY() + 5;

        for (String line : textObj.getLayoutLines()) {
            currentY += lineHeight;
            gc.fillText(line, textObj.getX() + 5, currentY);
        }

        // 如果选中，绘制边框
        if (selected) {
            drawSelectionBorder(gc, textObj);
        }
    }

    /**
     * 创建字体对象
     */
    private Font createFont(String family, double size, String style) {
        FontWeight weight = style.contains("BOLD") ? FontWeight.BOLD : FontWeight.NORMAL;
        FontPosture posture = style.contains("ITALIC") ? FontPosture.ITALIC : FontPosture.REGULAR;
        return Font.font(family, weight, posture, size);
    }

    /**
     * 绘制形状对象
     */
    private void drawShapeObject(GraphicsContext gc, ShapeObject shapeObj, boolean selected) {
        gc.setFill(shapeObj.getFillColorAsColor());
        gc.setStroke(shapeObj.getStrokeColorAsColor());
        gc.setLineWidth(shapeObj.getStrokeWidth());

        switch (shapeObj.getShapeType()) {
            case RECTANGLE:
                gc.fillRect(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());
                gc.strokeRect(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());
                break;
            case CIRCLE:
                double radius = Math.min(shapeObj.getWidth(), shapeObj.getHeight()) / 2;
                double centerX = shapeObj.getX() + shapeObj.getWidth() / 2;
                double centerY = shapeObj.getY() + shapeObj.getHeight() / 2;
                gc.fillOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
                gc.strokeOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
                break;
            case ELLIPSE:
                gc.fillOval(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());
                gc.strokeOval(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());
                break;
            case LINE:
                gc.strokeLine(shapeObj.getX(), shapeObj.getY(),
                        shapeObj.getX() + shapeObj.getWidth(), shapeObj.getY() + shapeObj.getHeight());
                break;
        }

        // 如果选中，绘制边框
        if (selected) {
            drawSelectionBorder(gc, shapeObj);
        }
    }

    /**
     * 绘制图片对象
     */
    private void drawImageObject(GraphicsContext gc, ImageObject imageObj, boolean selected) {
        try {
            Image image = new Image("file:" + imageObj.getImagePath());
            gc.drawImage(image, imageObj.getX(), imageObj.getY(), imageObj.getWidth(), imageObj.getHeight());
        } catch (Exception e) {
            // 如果图片加载失败，绘制占位符
            gc.setFill(Color.LIGHTGRAY);
            gc.fillRect(imageObj.getX(), imageObj.getY(), imageObj.getWidth(), imageObj.getHeight());
            gc.setFill(Color.BLACK);
            gc.fillText("[Image Not Found]", imageObj.getX() + 5, imageObj.getY() + 15);
        }

        // 如果选中，绘制边框
        if (selected) {
            drawSelectionBorder(gc, imageObj);
        }
    }

    /**
     * 绘制选中对象的边框和句柄
     */
    private void drawSelectionBorder(GraphicsContext gc, DrawableObject obj) {
        gc.setStroke(Color.BLUE);
        gc.setLineWidth(2);
        gc.strokeRect(obj.getX() - 2, obj.getY() - 2, obj.getWidth() + 4, obj.getHeight() + 4);

        // 绘制8个调整点
        drawResizeHandle(gc, obj.getX() - 4, obj.getY() - 4); // 左上
        drawResizeHandle(gc, obj.getX() + obj.getWidth(), obj.getY() - 4); // 右上
        drawResizeHandle(gc, obj.getX() - 4, obj.getY() + obj.getHeight()); // 左下
        drawResizeHandle(gc, obj.getX() + obj.getWidth(), obj.getY() + obj.getHeight()); // 右下
    }

    /**
     * 绘制调整点
     */
    private void drawResizeHandle(GraphicsContext gc, double x, double y) {
        gc.setFill(Color.BLUE);
        gc.fillRect(x, y, 8, 8);
        gc.setStroke(Color.WHITE);
        gc.setLineWidth(1);
        gc.strokeRect(x, y, 8, 8);
    }

    /**
     * 调整Canvas大小
     */
    public void resize(double width, double height) {
        canvas.setWidth(width);
        canvas.setHeight(height);
        setPrefSize(width, height);
        redraw();
    }
}

