/**
 * 10以内数的分与合绘制服务
 */

import { BaseDrawService } from '../../../core/draw/baseDraw';
import { getImage } from '../../../utils/index';
import { getRandomNumberColor } from '../../../constants/colors';

/**
 * 10以内数的分与合数据
 */
export interface NumberDecomposeData {
    problems: Array<{
        whole: number | null;
        part1: number | null;
        part2: number | null;
        imageIndex?: number;
        imageType?: 'fruits' | 'twelve-animals';
    }>;
    mode: 'with-image' | 'decompose' | 'compose';
}

/**
 * 10以内数的分与合绘制服务
 */
class NumberDecomposeDraw extends BaseDrawService {
    decomposeData: NumberDecomposeData | null = null;

    constructor(
        canvas: Canvas,
        ctx: RenderingContext,
        options?: Record<string, any>,
    ) {
        super(canvas, ctx, options);
        this.decomposeData = null;
    }

    /**
     * 绘制10以内数的分与合内容
     */
    async draw(decomposeData: NumberDecomposeData) {
        if (!decomposeData || !decomposeData.problems) {
            return;
        }

        this.decomposeData = decomposeData;
        this.prepareDraw();
        await this.drawHeaderAndDivider();
        await this.drawContent({
            canvas: this.canvas,
            ctx: this.ctx,
            decomposeData: this.decomposeData,
            canvasWidth: this.canvasWidth,
            startY: this.currentY,
        });
    }

    /**
     * 绘制内容区域
     */
    private async drawContent(params: {
        canvas: WechatMiniprogram.Canvas;
        ctx: RenderingContext;
        decomposeData: NumberDecomposeData;
        canvasWidth: number;
        startY: number;
    }): Promise<void> {
        const { canvas, ctx, decomposeData, canvasWidth, startY } = params;
        const { problems, mode } = decomposeData;

        if (mode === 'with-image') {
            await this.drawWithImageMode(
                canvas,
                ctx,
                problems,
                canvasWidth,
                startY,
            );
        } else if (mode === 'decompose') {
            await this.drawDecomposeOrComposeMode(
                ctx,
                problems,
                canvasWidth,
                startY,
                false,
            );
        } else if (mode === 'compose') {
            await this.drawDecomposeOrComposeMode(
                ctx,
                problems,
                canvasWidth,
                startY,
                true,
            );
        }
    }

    /**
     * 有图片模式：一行三列，总共三行（9个题目）
     */
    private async drawWithImageMode(
        canvas: WechatMiniprogram.Canvas,
        ctx: RenderingContext,
        problems: Array<{
            whole: number | null;
            part1: number | null;
            part2: number | null;
            imageIndex?: number;
            imageType?: 'fruits' | 'twelve-animals';
        }>,
        canvasWidth: number,
        startY: number,
    ) {
        const leftMargin = 30;
        const rightMargin = 30;
        const topMargin = 20;
        const boxSpacing = 20;
        const rowSpacing = 32;

        // 计算每个框的尺寸
        const availableWidth = canvasWidth - leftMargin - rightMargin;
        const boxWidth = (availableWidth - boxSpacing * 2) / 3; // 3列，2个间距
        const imageAreaHeight = 120; // 图片区域高度
        const treeAreaHeight = 80; // 二叉树区域高度

        let currentY = startY + topMargin;

        // 绘制3列3行
        for (let row = 0; row < 3; row++) {
            for (let col = 0; col < 3; col++) {
                const problemIndex = row * 3 + col;
                if (problemIndex >= problems.length) {
                    continue;
                }

                const problem = problems[problemIndex];
                const boxX = leftMargin + col * (boxWidth + boxSpacing);
                const boxY =
                    currentY +
                    row * (imageAreaHeight + treeAreaHeight + rowSpacing);

                // 绘制一个完整的题目框
                await this.drawWithImageProblem(
                    ctx,
                    canvas,
                    problem,
                    boxX,
                    boxY,
                    boxWidth,
                    imageAreaHeight,
                    treeAreaHeight,
                );
            }
        }
    }

    /**
     * 分模式/组合模式：一行3个，总共5行（15个题目）
     * @param isInverted true 为组合模式（倒置二叉树），false 为分模式（正常二叉树）
     */
    private async drawDecomposeOrComposeMode(
        ctx: RenderingContext,
        problems: Array<{
            whole: number | null;
            part1: number | null;
            part2: number | null;
        }>,
        canvasWidth: number,
        startY: number,
        isInverted: boolean,
    ) {
        const leftMargin = 30;
        const rightMargin = 30;
        const topMargin = 20;
        const boxSpacing = 15;
        const rowSpacing = 140;

        // 计算每个框的尺寸
        const availableWidth = canvasWidth - leftMargin - rightMargin;
        const boxWidth = (availableWidth - boxSpacing * 2) / 3; // 3列，2个间距
        const boxHeight = 80; // 二叉树区域高度

        let currentY = startY + topMargin;

        // 绘制3列5行
        for (let row = 0; row < 5; row++) {
            for (let col = 0; col < 3; col++) {
                const problemIndex = row * 3 + col;
                if (problemIndex >= problems.length) {
                    continue;
                }

                const problem = problems[problemIndex];
                const boxX = leftMargin + col * (boxWidth + boxSpacing);
                const boxY = currentY + row * rowSpacing;

                // 绘制二叉树
                this.drawTree(
                    ctx,
                    problem,
                    boxX,
                    boxY,
                    boxWidth,
                    boxHeight,
                    isInverted,
                );
            }
        }
    }

    /**
     * 绘制有图片模式的单个题目
     */
    private async drawWithImageProblem(
        ctx: RenderingContext,
        canvas: WechatMiniprogram.Canvas,
        problem: {
            whole: number | null;
            part1: number | null;
            part2: number | null;
            imageIndex?: number;
            imageType?: 'fruits' | 'twelve-animals';
        },
        boxX: number,
        boxY: number,
        boxWidth: number,
        imageAreaHeight: number,
        treeAreaHeight: number,
    ) {
        const borderRadius = 12;

        // 绘制实线框（只绘制图片区域的框）
        ctx.strokeStyle = '#333';
        ctx.lineWidth = 1;
        this.drawRoundedRectInternal(
            ctx,
            boxX,
            boxY,
            boxWidth,
            imageAreaHeight,
            borderRadius,
            false,
        );

        // 图片区域（增加底部间距，避免与二叉树根节点重叠）
        const imageBottomPadding = 20; // 图片区域底部额外间距
        const effectiveImageHeight = imageAreaHeight - imageBottomPadding;

        if (problem.imageIndex && problem.imageType && problem.whole) {
            await this.drawImagesInBox(
                ctx,
                canvas,
                problem.whole,
                problem.imageIndex,
                problem.imageType,
                boxX,
                boxY,
                boxWidth,
                effectiveImageHeight,
            );
        }

        // 二叉树区域（增加与图片区域的间距）
        const treeTopSpacing = -5; // 二叉树区域顶部间距
        const treeY = boxY + imageAreaHeight + treeTopSpacing;
        this.drawTree(
            ctx,
            problem,
            boxX,
            treeY,
            boxWidth,
            treeAreaHeight,
            false, // 不是倒置
        );
    }

    /**
     * 绘制二叉树结构
     * @param isInverted 是否倒置（组合模式为true）
     */
    private drawTree(
        ctx: RenderingContext,
        problem: {
            whole: number | null;
            part1: number | null;
            part2: number | null;
        },
        boxX: number,
        boxY: number,
        boxWidth: number,
        boxHeight: number,
        isInverted: boolean,
    ) {
        const nodeRadius = 18;
        const nodeSpacing = 40; // 节点之间的水平间距
        const verticalSpacing = 70; // 根节点和子节点的垂直间距

        if (isInverted) {
            // 组合模式：倒置二叉树
            // 顶部：两个子节点（part1, part2）
            // 底部：根节点（whole，需要填写）

            const centerX = boxX + boxWidth / 2;
            const topY = boxY + boxHeight / 2 - verticalSpacing / 2;
            const bottomY = boxY + boxHeight / 2 + verticalSpacing / 2;

            // 绘制两个子节点（顶部）
            const leftNodeX = centerX - nodeSpacing / 2 - nodeRadius;
            const rightNodeX = centerX + nodeSpacing / 2 + nodeRadius;

            // 左子节点
            this.drawNode(ctx, leftNodeX, topY, nodeRadius, problem.part1);
            // 右子节点
            this.drawNode(ctx, rightNodeX, topY, nodeRadius, problem.part2);

            // 绘制根节点（底部）
            this.drawNode(ctx, centerX, bottomY, nodeRadius, problem.whole);

            // 绘制连接线（从子节点到根节点）
            ctx.strokeStyle = '#333';
            ctx.lineWidth = 2;
            ctx.beginPath();
            ctx.moveTo(leftNodeX, topY + nodeRadius);
            ctx.lineTo(centerX, bottomY - nodeRadius);
            ctx.stroke();

            ctx.beginPath();
            ctx.moveTo(rightNodeX, topY + nodeRadius);
            ctx.lineTo(centerX, bottomY - nodeRadius);
            ctx.stroke();
        } else {
            // 分解模式：正常二叉树
            // 顶部：根节点（whole）
            // 底部：两个子节点（part1, part2，其中一个需要填写）

            const centerX = boxX + boxWidth / 2;
            const topY = boxY + boxHeight / 2 - verticalSpacing / 2;
            const bottomY = boxY + boxHeight / 2 + verticalSpacing / 2;

            // 绘制根节点（顶部）
            this.drawNode(ctx, centerX, topY, nodeRadius, problem.whole);

            // 绘制两个子节点（底部）
            const leftNodeX = centerX - nodeSpacing / 2 - nodeRadius;
            const rightNodeX = centerX + nodeSpacing / 2 + nodeRadius;

            // 左子节点
            this.drawNode(ctx, leftNodeX, bottomY, nodeRadius, problem.part1);
            // 右子节点
            this.drawNode(ctx, rightNodeX, bottomY, nodeRadius, problem.part2);

            // 绘制连接线（从根节点到子节点）
            ctx.strokeStyle = '#333';
            ctx.lineWidth = 2;
            ctx.beginPath();
            ctx.moveTo(centerX, topY + nodeRadius);
            ctx.lineTo(leftNodeX, bottomY - nodeRadius);
            ctx.stroke();

            ctx.beginPath();
            ctx.moveTo(centerX, topY + nodeRadius);
            ctx.lineTo(rightNodeX, bottomY - nodeRadius);
            ctx.stroke();
        }
    }

    /**
     * 绘制节点（圆圈和数字）
     */
    private drawNode(
        ctx: RenderingContext,
        x: number,
        y: number,
        radius: number,
        value: number | null,
    ) {
        // 绘制圆角正方形
        const size = radius * 2; // 正方形边长
        const cornerRadius = 8; // 圆角半径
        const halfSize = size / 2;

        ctx.fillStyle = '#fff';
        ctx.strokeStyle = '#333';
        ctx.lineWidth = 2;

        // 绘制圆角矩形
        ctx.beginPath();
        ctx.moveTo(x - halfSize + cornerRadius, y - halfSize);
        ctx.lineTo(x + halfSize - cornerRadius, y - halfSize);
        ctx.quadraticCurveTo(
            x + halfSize,
            y - halfSize,
            x + halfSize,
            y - halfSize + cornerRadius,
        );
        ctx.lineTo(x + halfSize, y + halfSize - cornerRadius);
        ctx.quadraticCurveTo(
            x + halfSize,
            y + halfSize,
            x + halfSize - cornerRadius,
            y + halfSize,
        );
        ctx.lineTo(x - halfSize + cornerRadius, y + halfSize);
        ctx.quadraticCurveTo(
            x - halfSize,
            y + halfSize,
            x - halfSize,
            y + halfSize - cornerRadius,
        );
        ctx.lineTo(x - halfSize, y - halfSize + cornerRadius);
        ctx.quadraticCurveTo(
            x - halfSize,
            y - halfSize,
            x - halfSize + cornerRadius,
            y - halfSize,
        );
        ctx.closePath();
        ctx.fill();
        ctx.stroke();

        // 如果有值，绘制数字
        if (value !== null) {
            ctx.fillStyle = getRandomNumberColor();
            ctx.font = `bold ${24}px "Microsoft Yahei"`;
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            ctx.fillText(String(value), x, y);
        }
    }

    /**
     * 在框内绘制多张图片
     */
    private async drawImagesInBox(
        ctx: RenderingContext,
        canvas: WechatMiniprogram.Canvas,
        count: number,
        imageIndex: number,
        imageType: 'fruits' | 'twelve-animals',
        boxX: number,
        boxY: number,
        boxWidth: number,
        boxHeight: number,
    ) {
        // 图片配置
        const imageConfig = {
            'twelve-animals': {
                folder: 'twelve-animals',
                maxIndex: 12,
            },
            fruits: {
                folder: 'fruits',
                maxIndex: 22,
            },
        };

        const config = imageConfig[imageType] || imageConfig['twelve-animals'];

        const horizontalPadding = 5;
        const verticalPadding = 10;
        const availableWidth = boxWidth - horizontalPadding * 2;
        const availableHeight = boxHeight - verticalPadding * 2;

        // 根据数量确定每行的图片数和图片大小
        let imagesPerRow: number;
        let imageSize: number;

        if (count <= 4) {
            imagesPerRow = count <= 2 ? count : 2;
            imageSize =
                Math.min(availableWidth / imagesPerRow, availableHeight / 2) -
                4;
        } else if (count <= 6) {
            imagesPerRow = 3;
            imageSize = Math.min(availableWidth / 3, availableHeight / 2) - 4;
        } else {
            imagesPerRow = 3;
            imageSize = Math.min(availableWidth / 3, availableHeight / 3) - 4;
        }

        const rows = Math.ceil(count / imagesPerRow);
        const imageSpacing =
            (availableWidth - imageSize * imagesPerRow) / (imagesPerRow + 1);
        const rowSpacing =
            rows > 1 ? (availableHeight - imageSize * rows) / (rows + 1) : 0;

        // 加载图片
        let boxImage: any = null;
        try {
            const imagePath = `/mathPages/shared/assets/${config.folder}/${imageIndex}.png`;
            boxImage = await getImage(canvas, imagePath);
        } catch (error) {
            console.error(`加载${config.folder}/${imageIndex}图片失败:`, error);
            return;
        }

        // 绘制图片
        for (let i = 0; i < count; i++) {
            const row = Math.floor(i / imagesPerRow);
            const col = i % imagesPerRow;

            const imageX =
                boxX +
                horizontalPadding +
                imageSpacing +
                col * (imageSize + imageSpacing);
            const imageY =
                boxY +
                verticalPadding +
                // 这两段代码是用于计算每一张图片在Y轴方向上的实际位置（imageY 变量）
                // 第一行：如果有多于一行，行间用 rowSpacing，否则单行时图片整体垂直居中排列。
                (rows > 1 ? rowSpacing : (availableHeight - imageSize) / 2) +
                // 第二行：加上具体第 row 行的纵向偏移（每张图片的高度加上行间距，再乘以行号）。
                row * (imageSize + (rows > 1 ? rowSpacing : 0));

            if (boxImage) {
                // 计算图片高度（等比例缩放）
                // @ts-ignore - 微信小程序图片对象有 width 和 height 属性
                const scaledHeight =
                    (boxImage.height / boxImage.width) * imageSize;

                ctx.drawImage(
                    boxImage,
                    imageX,
                    imageY,
                    imageSize,
                    scaledHeight,
                );
            }
        }
    }

    /**
     * 绘制圆角矩形（虚线边框）
     */
    private drawRoundedRectInternal(
        ctx: RenderingContext,
        x: number,
        y: number,
        width: number,
        height: number,
        radius: number,
        isDashed: boolean = false,
    ) {
        ctx.beginPath();
        ctx.moveTo(x + radius, y);
        ctx.lineTo(x + width - radius, y);
        ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
        ctx.lineTo(x + width, y + height - radius);
        ctx.quadraticCurveTo(
            x + width,
            y + height,
            x + width - radius,
            y + height,
        );
        ctx.lineTo(x + radius, y + height);
        ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
        ctx.lineTo(x, y + radius);
        ctx.quadraticCurveTo(x, y, x + radius, y);
        ctx.closePath();

        if (isDashed) {
            ctx.setLineDash([6 / 3, 6 / 3]); // 约2px的虚线
        } else {
            ctx.setLineDash([]);
        }
        ctx.stroke();
        ctx.setLineDash([]); // 重置为实线
    }
}

export default NumberDecomposeDraw;
