package dev.bytevibe.hyperpoint;

import javafx.animation.*;
import javafx.geometry.Bounds;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;

/**
 * 全屏演示窗口，支持翻页和动画效果
 */
public class PresentationWindow {
    private final Slide slide;
    private final Stage stage;
    private final Canvas canvas;
    private final StackPane root;
    private int currentPageIndex = 0;
    private TransitionEffect currentTransition = TransitionEffect.FADE;
    private boolean isTransitioning = false;

    public PresentationWindow(Slide slide, TransitionEffect transition) {
        this.slide = slide;
        this.currentTransition = transition;
        this.stage = new Stage();
        this.canvas = new Canvas();
        this.root = new StackPane();

        initializeStage();
    }

    private void initializeStage() {
        // 页面标准宽高比 (4:3) - 使用与编辑界面相同的尺寸
        final double PAGE_WIDTH = DrawingCanvas.PAGE_WIDTH;   // 1024
        final double PAGE_HEIGHT = DrawingCanvas.PAGE_HEIGHT; // 768

        // 设置全屏，获取屏幕分辨率
        stage.setFullScreen(true);
        stage.setFullScreenExitHint("");
        stage.initStyle(StageStyle.UNDECORATED);

        // 绑定Canvas大小到root，Canvas会根据root大小自动调整
        canvas.widthProperty().bind(root.widthProperty());
        canvas.heightProperty().bind(root.heightProperty());

        // 添加键盘和鼠标事件处理
        root.setOnKeyPressed(this::handleKeyEvent);
        root.setOnMouseClicked(this::handleMouseClick);

        root.getChildren().add(canvas);
        root.setStyle("-fx-background-color: #000000;");
        root.setFocusTraversable(true);

        Scene scene = new Scene(root);
        stage.setScene(scene);

        // 监听Scene大小变化，计算缩放因子
        scene.widthProperty().addListener((obs, oldVal, newVal) -> drawCurrentPage(null));
        scene.heightProperty().addListener((obs, oldVal, newVal) -> drawCurrentPage(null));

        // 显示第一页
        drawCurrentPage(null);
    }

    /**
     * 显示演示窗口
     */
    public void show() {
        stage.show();
        root.requestFocus();
    }

    /**
     * 处理键盘事件
     */
    private void handleKeyEvent(KeyEvent event) {
        if (event.getCode() == KeyCode.RIGHT || event.getCode() == KeyCode.SPACE) {
            nextPage();
        } else if (event.getCode() == KeyCode.LEFT) {
            previousPage();
        } else if (event.getCode() == KeyCode.ESCAPE) {
            exitPresentation();
        }
    }

    /**
     * 处理鼠标点击事件
     */
    private void handleMouseClick(MouseEvent event) {
        if (event.getClickCount() == 1) {
            nextPage();
        }
    }

    /**
     * 下一页
     */
    private void nextPage() {
        if (isTransitioning || currentPageIndex >= slide.getPages().size() - 1) {
            return;
        }
        currentPageIndex++;
        playTransition(currentTransition);
    }

    /**
     * 上一页
     */
    private void previousPage() {
        if (isTransitioning || currentPageIndex <= 0) {
            return;
        }
        currentPageIndex--;
        playTransition(currentTransition);
    }

    /**
     * 播放过渡动画
     */
    private void playTransition(TransitionEffect effect) {
        isTransitioning = true;

        switch (effect) {
            case FADE:
                playFadeTransition();
                break;
            case PUSH_LEFT:
                playPushTransition(-canvas.getWidth(), 0);
                break;
            case PUSH_RIGHT:
                playPushTransition(canvas.getWidth(), 0);
                break;
            case PUSH_DOWN:
                playPushTransition(0, canvas.getHeight());
                break;
            case PUSH_UP:
                playPushTransition(0, -canvas.getHeight());
                break;
            case ZOOM_IN:
                playZoomTransition(0.5, 1.0);
                break;
            case ZOOM_OUT:
                playZoomTransition(1.0, 0.5);
                break;
            case ROTATE:
                playRotateTransition();
                break;
            default:
                drawCurrentPage(null);
                isTransitioning = false;
        }
    }

    /**
     * 淡出淡入动画
     */
    private void playFadeTransition() {
        int duration = currentTransition.getDuration();
        int halfDuration = duration / 2;

        // 保存当前页面索引
        int previousPageIndex = currentPageIndex - 1;
        if (previousPageIndex < 0) previousPageIndex = slide.getPages().size() - 1;

        // 淡出旧页面，显示黑屏，淡入新页面
        AnimationTimer animationTimer = new AnimationTimer() {
            private long startTime = System.currentTimeMillis();
            private final long fadeOutDuration = halfDuration;
            private final long fadeInDuration = halfDuration;

            @Override
            public void handle(long now) {
                long elapsed = System.currentTimeMillis() - startTime;

                if (elapsed < fadeOutDuration) {
                    // 淡出阶段
                    double progress = (double) elapsed / fadeOutDuration;
                    drawFadeTransition(progress, true);
                } else if (elapsed < fadeOutDuration + fadeInDuration) {
                    // 淡入阶段
                    double progress = (double) (elapsed - fadeOutDuration) / fadeInDuration;
                    drawFadeTransition(progress, false);
                } else {
                    // 动画完成
                    drawCurrentPage(null);
                    isTransitioning = false;
                    stop();
                }
            }
        };

        animationTimer.start();
    }

    /**
     * 绘制淡出淡入过渡
     */
    private void drawFadeTransition(double progress, boolean fadeOut) {
        GraphicsContext gc = canvas.getGraphicsContext2D();
        double canvasWidth = canvas.getWidth();
        double canvasHeight = canvas.getHeight();

        final double PAGE_WIDTH = DrawingCanvas.PAGE_WIDTH;
        final double PAGE_HEIGHT = DrawingCanvas.PAGE_HEIGHT;

        double scaleX = canvasWidth / PAGE_WIDTH;
        double scaleY = canvasHeight / PAGE_HEIGHT;
        double scale = Math.min(scaleX, scaleY);

        double scaledWidth = PAGE_WIDTH * scale;
        double scaledHeight = PAGE_HEIGHT * scale;

        double offsetX = (canvasWidth - scaledWidth) / 2;
        double offsetY = (canvasHeight - scaledHeight) / 2;

        if (fadeOut) {
            // 绘制当前页面并淡出
            drawCurrentPage(null);
            gc.setFill(Color.BLACK.interpolate(Color.TRANSPARENT, 1 - progress));
            gc.fillRect(0, 0, canvasWidth, canvasHeight);
        } else {
            // 绘制黑屏并淡入下一页
            gc.setFill(Color.BLACK);
            gc.fillRect(0, 0, canvasWidth, canvasHeight);

            gc.setFill(Color.WHITE);
            gc.fillRect(offsetX, offsetY, scaledWidth, scaledHeight);

            gc.save();
            gc.translate(offsetX, offsetY);
            gc.scale(scale, scale);

            SlidePage page = slide.getPages().get(currentPageIndex);
            for (DrawableObject obj : page.getPageContent().getDrawableObjects()) {
                drawObject(gc, obj);
            }

            gc.restore();

            // 淡入效果
            gc.setFill(Color.color(1, 1, 1, 1 - progress));
            gc.fillRect(0, 0, canvasWidth, canvasHeight);
        }
    }

    /**
     * 推送动画
     */
    private void playPushTransition(double offsetX, double offsetY) {
        int duration = currentTransition.getDuration();

        AnimationTimer animationTimer = new AnimationTimer() {
            private long startTime = System.currentTimeMillis();

            @Override
            public void handle(long now) {
                long elapsed = System.currentTimeMillis() - startTime;

                if (elapsed < duration) {
                    double progress = (double) elapsed / duration;
                    drawPushTransition(progress, offsetX, offsetY);
                } else {
                    drawCurrentPage(null);
                    isTransitioning = false;
                    stop();
                }
            }
        };

        animationTimer.start();
    }

    /**
     * 绘制推送过渡
     */
    private void drawPushTransition(double progress, double offsetX, double offsetY) {
        GraphicsContext gc = canvas.getGraphicsContext2D();
        double canvasWidth = canvas.getWidth();
        double canvasHeight = canvas.getHeight();

        final double PAGE_WIDTH = DrawingCanvas.PAGE_WIDTH;
        final double PAGE_HEIGHT = DrawingCanvas.PAGE_HEIGHT;

        double scaleX = canvasWidth / PAGE_WIDTH;
        double scaleY = canvasHeight / PAGE_HEIGHT;
        double scale = Math.min(scaleX, scaleY);

        double scaledWidth = PAGE_WIDTH * scale;
        double scaledHeight = PAGE_HEIGHT * scale;

        double centerOffsetX = (canvasWidth - scaledWidth) / 2;
        double centerOffsetY = (canvasHeight - scaledHeight) / 2;

        // 清空背景
        gc.setFill(Color.BLACK);
        gc.fillRect(0, 0, canvasWidth, canvasHeight);

        // 获取前一页索引（确保有效）
        int prevPageIndex = currentPageIndex - 1;
        if (prevPageIndex < 0) {
            prevPageIndex = slide.getPages().size() - 1;  // 循环到最后一页
        }

        // 绘制旧页面
        SlidePage prevPage = slide.getPages().get(prevPageIndex);
        double slideOffsetX = offsetX * progress;
        double slideOffsetY = offsetY * progress;

        gc.save();
        gc.translate(centerOffsetX + slideOffsetX, centerOffsetY + slideOffsetY);
        gc.scale(scale, scale);
        gc.setFill(Color.WHITE);
        gc.fillRect(0, 0, PAGE_WIDTH, PAGE_HEIGHT);
        for (DrawableObject obj : prevPage.getPageContent().getDrawableObjects()) {
            drawObject(gc, obj);
        }
        gc.restore();

        // 绘制新页面推入
        SlidePage newPage = slide.getPages().get(currentPageIndex);
        double newPageOffsetX = centerOffsetX - offsetX * (1 - progress);
        double newPageOffsetY = centerOffsetY - offsetY * (1 - progress);

        gc.save();
        gc.translate(newPageOffsetX, newPageOffsetY);
        gc.scale(scale, scale);
        gc.setFill(Color.WHITE);
        gc.fillRect(0, 0, PAGE_WIDTH, PAGE_HEIGHT);
        for (DrawableObject obj : newPage.getPageContent().getDrawableObjects()) {
            drawObject(gc, obj);
        }
        gc.restore();
    }

    /**
     * 缩放动画
     */
    private void playZoomTransition(double startScale, double endScale) {
        int duration = currentTransition.getDuration();

        AnimationTimer animationTimer = new AnimationTimer() {
            private long startTime = System.currentTimeMillis();

            @Override
            public void handle(long now) {
                long elapsed = System.currentTimeMillis() - startTime;

                if (elapsed < duration) {
                    double progress = (double) elapsed / duration;
                    double currentScale = startScale + (endScale - startScale) * progress;
                    drawZoomTransition(currentScale, progress);
                } else {
                    drawCurrentPage(null);
                    isTransitioning = false;
                    stop();
                }
            }
        };

        animationTimer.start();
    }

    /**
     * 绘制缩放过渡
     */
    private void drawZoomTransition(double zoomScale, double progress) {
        GraphicsContext gc = canvas.getGraphicsContext2D();
        double canvasWidth = canvas.getWidth();
        double canvasHeight = canvas.getHeight();

        final double PAGE_WIDTH = DrawingCanvas.PAGE_WIDTH;
        final double PAGE_HEIGHT = DrawingCanvas.PAGE_HEIGHT;

        double scaleX = canvasWidth / PAGE_WIDTH;
        double scaleY = canvasHeight / PAGE_HEIGHT;
        double scale = Math.min(scaleX, scaleY);

        double scaledWidth = PAGE_WIDTH * scale;
        double scaledHeight = PAGE_HEIGHT * scale;

        double offsetX = (canvasWidth - scaledWidth) / 2;
        double offsetY = (canvasHeight - scaledHeight) / 2;

        // 清空背景
        gc.setFill(Color.BLACK);
        gc.fillRect(0, 0, canvasWidth, canvasHeight);

        // 获取前一页索引（确保有效）
        int prevPageIndex = currentPageIndex - 1;
        if (prevPageIndex < 0) {
            prevPageIndex = slide.getPages().size() - 1;  // 循环到最后一页
        }

        // 绘制旧页面，逐渐缩小
        SlidePage prevPage = slide.getPages().get(prevPageIndex);
        double oldPageScale = scale * (1 - progress * 0.3);  // 缩小30%
        double oldPageWidth = PAGE_WIDTH * oldPageScale;
        double oldPageHeight = PAGE_HEIGHT * oldPageScale;
        double oldPageOffsetX = (canvasWidth - oldPageWidth) / 2;
        double oldPageOffsetY = (canvasHeight - oldPageHeight) / 2;

        gc.save();
        gc.translate(oldPageOffsetX, oldPageOffsetY);
        gc.scale(oldPageScale / scale, oldPageScale / scale);
        gc.setFill(Color.WHITE);
        gc.fillRect(0, 0, PAGE_WIDTH, PAGE_HEIGHT);
        for (DrawableObject obj : prevPage.getPageContent().getDrawableObjects()) {
            drawObject(gc, obj);
        }
        gc.restore();

        // 绘制新页面，逐渐放大
        SlidePage newPage = slide.getPages().get(currentPageIndex);
        double newPageScale = scale * (0.7 + progress * 0.3);  // 从70%放大到100%
        double newPageWidth = PAGE_WIDTH * newPageScale;
        double newPageHeight = PAGE_HEIGHT * newPageScale;
        double newPageOffsetX = (canvasWidth - newPageWidth) / 2;
        double newPageOffsetY = (canvasHeight - newPageHeight) / 2;

        gc.save();
        gc.translate(newPageOffsetX, newPageOffsetY);
        gc.scale(newPageScale / scale, newPageScale / scale);
        gc.setFill(Color.WHITE);
        gc.fillRect(0, 0, PAGE_WIDTH, PAGE_HEIGHT);
        for (DrawableObject obj : newPage.getPageContent().getDrawableObjects()) {
            drawObject(gc, obj);
        }
        gc.restore();
    }

    /**
     * 旋转动画
     */
    private void playRotateTransition() {
        int duration = currentTransition.getDuration();

        AnimationTimer animationTimer = new AnimationTimer() {
            private long startTime = System.currentTimeMillis();

            @Override
            public void handle(long now) {
                long elapsed = System.currentTimeMillis() - startTime;

                if (elapsed < duration) {
                    double progress = (double) elapsed / duration;
                    double rotation = progress * 360;  // 360度旋转
                    drawRotateTransition(rotation, progress);
                } else {
                    drawCurrentPage(null);
                    isTransitioning = false;
                    stop();
                }
            }
        };

        animationTimer.start();
    }

    /**
     * 绘制旋转过渡
     */
    private void drawRotateTransition(double rotation, double progress) {
        GraphicsContext gc = canvas.getGraphicsContext2D();
        double canvasWidth = canvas.getWidth();
        double canvasHeight = canvas.getHeight();

        final double PAGE_WIDTH = DrawingCanvas.PAGE_WIDTH;
        final double PAGE_HEIGHT = DrawingCanvas.PAGE_HEIGHT;

        double scaleX = canvasWidth / PAGE_WIDTH;
        double scaleY = canvasHeight / PAGE_HEIGHT;
        double scale = Math.min(scaleX, scaleY);

        double scaledWidth = PAGE_WIDTH * scale;
        double scaledHeight = PAGE_HEIGHT * scale;

        double offsetX = (canvasWidth - scaledWidth) / 2;
        double offsetY = (canvasHeight - scaledHeight) / 2;

        // 清空背景
        gc.setFill(Color.BLACK);
        gc.fillRect(0, 0, canvasWidth, canvasHeight);

        // 绘制旋转的页面
        SlidePage newPage = slide.getPages().get(currentPageIndex);

        gc.save();
        // 移到中心，旋转，再移回
        double centerX = offsetX + scaledWidth / 2;
        double centerY = offsetY + scaledHeight / 2;

        gc.translate(centerX, centerY);
        gc.rotate(rotation);
        gc.translate(-scaledWidth / 2, -scaledHeight / 2);
        gc.scale(scale, scale);

        gc.setFill(Color.WHITE);
        gc.fillRect(0, 0, PAGE_WIDTH, PAGE_HEIGHT);
        for (DrawableObject obj : newPage.getPageContent().getDrawableObjects()) {
            drawObject(gc, obj);
        }

        gc.restore();
    }

    /**
     * 绘制当前页面
     */
    private void drawCurrentPage(Animation animation) {
        if (currentPageIndex < 0 || currentPageIndex >= slide.getPages().size()) {
            return;
        }

        GraphicsContext gc = canvas.getGraphicsContext2D();
        double canvasWidth = canvas.getWidth();
        double canvasHeight = canvas.getHeight();

        // 页面标准宽高比
        final double PAGE_WIDTH = DrawingCanvas.PAGE_WIDTH;
        final double PAGE_HEIGHT = DrawingCanvas.PAGE_HEIGHT;

        // 计算缩放因子，保持宽高比
        double scaleX = canvasWidth / PAGE_WIDTH;
        double scaleY = canvasHeight / PAGE_HEIGHT;
        double scale = Math.min(scaleX, scaleY);

        // 计算内容区域的实际宽高
        double scaledWidth = PAGE_WIDTH * scale;
        double scaledHeight = PAGE_HEIGHT * scale;

        // 计算居中偏移
        double offsetX = (canvasWidth - scaledWidth) / 2;
        double offsetY = (canvasHeight - scaledHeight) / 2;

        // 清空背景（黑色）
        gc.setFill(Color.BLACK);
        gc.fillRect(0, 0, canvasWidth, canvasHeight);

        // 白色背景区域
        gc.setFill(Color.WHITE);
        gc.fillRect(offsetX, offsetY, scaledWidth, scaledHeight);

        SlidePage page = slide.getPages().get(currentPageIndex);

        // 保存绘图上下文
        gc.save();

        // 应用缩放和平移变换
        gc.translate(offsetX, offsetY);
        gc.scale(scale, scale);

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

        gc.restore();

        // 绘制页码（不受缩放影响）
        drawPageNumber(gc, canvasWidth, canvasHeight);
    }

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

    /**
     * 绘制文本对象
     */
    private void drawTextObject(GraphicsContext gc, TextObject textObj) {
        gc.setFill(textObj.getTextColorAsColor());
        gc.setFont(new javafx.scene.text.Font(textObj.getFontFamily(), textObj.getFontSize()));

        double lineHeight = textObj.getFontSize() * 1.2;
        double currentY = textObj.getY();

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

    /**
     * 绘制形状对象
     */
    private void drawShapeObject(GraphicsContext gc, ShapeObject shapeObj) {
        gc.setFill(Color.web("#" + shapeObj.getFillColor()));
        gc.setStroke(Color.web("#" + shapeObj.getStrokeColor()));
        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;
                gc.fillOval(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());
                gc.strokeOval(shapeObj.getX(), shapeObj.getY(), shapeObj.getWidth(), shapeObj.getHeight());
                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;
        }
    }

    /**
     * 绘制图片对象
     */
    private void drawImageObject(GraphicsContext gc, ImageObject imgObj) {
        try {
            javafx.scene.image.Image image = new javafx.scene.image.Image("file:" + imgObj.getImagePath());
            gc.drawImage(image, imgObj.getX(), imgObj.getY(), imgObj.getWidth(), imgObj.getHeight());
        } catch (Exception e) {
            // 图片加载失败，显示占位符
            gc.setFill(Color.LIGHTGRAY);
            gc.fillRect(imgObj.getX(), imgObj.getY(), imgObj.getWidth(), imgObj.getHeight());
            gc.setFill(Color.BLACK);
            gc.fillText("图片加载失败", imgObj.getX() + 10, imgObj.getY() + 20);
        }
    }

    /**
     * 绘制页码（不受缩放影响）
     */
    private void drawPageNumber(GraphicsContext gc, double canvasWidth, double canvasHeight) {
        gc.setFill(Color.BLACK);
        gc.setFont(new javafx.scene.text.Font(16));
        String pageNum = String.format("%d / %d", currentPageIndex + 1, slide.getPages().size());
        gc.fillText(pageNum, canvasWidth - 100, canvasHeight - 20);
    }

    /**
     * 设置翻页动画
     */
    public void setTransitionEffect(TransitionEffect effect) {
        this.currentTransition = effect;
    }

    /**
     * 退出演示
     */
    private void exitPresentation() {
        stage.close();
    }

    /**
     * 获取舞台
     */
    public Stage getStage() {
        return stage;
    }
}

