/**
 * 线条识别绘制服务
 */

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

/**
 * 线条类型
 */
export type LineType = 'straight' | 'dashed' | 'wavy' | 'zigzag' | 'spiral';

/**
 * 线条类型配置
 */
export interface LineTypeConfig {
    type: LineType;
    name: string;
    color: string;
}

/**
 * 线条识别数据
 */
export interface LineRecognitionData {
    /** 预览区域的5个线条配置（随机排列） */
    referenceLines: LineTypeConfig[];
    /** 练习区域的16个色块（2列×8行） */
    practiceBlocks: Array<{
        color: string;
        lineType: LineType;
        x: number; // 相对于列的X偏移（错落感）
        y: number; // 相对于行的Y偏移（错落感）
    }>;
}

/**
 * 线条识别绘制服务
 */
class LineRecognitionDraw extends BaseDrawService {
    lineData: LineRecognitionData | null = null;
    lineStrokeStyle: string = '#222'; // 线条颜色
    lineWidth: number = 2; // 线条宽度
    spiralLineImage: any = null; // 电话线图片对象
    private spiralLineImagePromise: Promise<any> | null = null; // 图片加载Promise

    constructor(
        canvas: Canvas,
        ctx: RenderingContext,
        options?: Record<string, any>,
    ) {
        super(canvas, ctx, options);
        // 在构造函数中启动图片加载
        this.loadSpiralLineImage();
    }

    /**
     * 加载电话线图片
     */
    private loadSpiralLineImage() {
        if (!this.spiralLineImagePromise) {
            const imagePath = `/focusPages/shared/aeests/imgs/spiral-line.png`;
            this.spiralLineImagePromise = getImage(this.canvas, imagePath).then(
                (image) => {
                    this.spiralLineImage = image;
                    return image;
                },
            );
        }
        return this.spiralLineImagePromise;
    }

    /**
     * 绘制线条识别内容
     */
    async draw(lineData: LineRecognitionData) {
        if (!lineData || !lineData.referenceLines || !lineData.practiceBlocks) {
            return;
        }

        // 确保电话线图片已加载
        if (!this.spiralLineImage) {
            await this.loadSpiralLineImage();
        }

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

    /**
     * 绘制直线
     */
    private drawStraightLine(
        ctx: RenderingContext,
        x: number,
        y: number,
        width: number,
    ) {
        ctx.strokeStyle = this.lineStrokeStyle;
        ctx.lineWidth = this.lineWidth;
        ctx.setLineDash([]);
        ctx.beginPath();
        ctx.moveTo(x, y);
        ctx.lineTo(x + width, y);
        ctx.stroke();
    }

    /**
     * 绘制虚线
     */
    private drawDashedLine(
        ctx: RenderingContext,
        x: number,
        y: number,
        width: number,
    ) {
        ctx.strokeStyle = this.lineStrokeStyle;
        ctx.lineWidth = this.lineWidth;
        ctx.setLineDash([6, 4]);
        ctx.beginPath();
        ctx.moveTo(x, y);
        ctx.lineTo(x + width, y);
        ctx.stroke();
        ctx.setLineDash([]);
    }

    /**
     * 绘制波浪线
     */
    private drawWavyLine(
        ctx: RenderingContext,
        x: number,
        y: number,
        width: number,
    ) {
        ctx.strokeStyle = this.lineStrokeStyle;
        ctx.lineWidth = this.lineWidth;
        ctx.setLineDash([]);
        ctx.beginPath();
        const radius = 8; // 波浪半径
        const turns = 5; // 波浪圈数
        const points = 120; // 点数
        const startX = x;
        const endX = x + width;

        ctx.moveTo(startX, y);
        for (let i = 0; i <= points; i++) {
            const progress = i / points;
            const currentX = startX + (endX - startX) * progress;
            const angle = progress * turns * Math.PI * 2;
            const currentY = y + Math.sin(angle) * radius;
            ctx.lineTo(currentX, currentY);
        }
        ctx.stroke();
    }

    /**
     * 绘制锯齿线
     */
    private drawZigzagLine(
        ctx: RenderingContext,
        x: number,
        y: number,
        width: number,
    ) {
        ctx.strokeStyle = this.lineStrokeStyle;
        ctx.lineWidth = this.lineWidth;
        ctx.setLineDash([]); // 实线
        ctx.beginPath();

        const segmentLength = 12; // 每段长度
        const amplitude = 7; // 波峰/波谷高度

        // 第一个点为波峰顶点
        let currentX = x;
        let currentY = y - amplitude;
        ctx.moveTo(currentX, currentY);

        // 计算一共能画多少完整段，两点之间斜线斜率为±1（45度）
        const nSegments = Math.ceil(width / segmentLength);

        for (let i = 0; i < nSegments; i++) {
            // 下一点横坐标
            let nextX = currentX + segmentLength;
            // 最后一个点不能超过终点，且如正好到终点，高度需计算
            if (nextX > x + width) {
                nextX = x + width;
            }
            // 交替：偶数索引连向波谷，奇数索引连向波峰
            let nextY;
            if (i % 2 === 0) {
                nextY = y + amplitude; // 波谷
            } else {
                nextY = y - amplitude; // 波峰
            }
            // 如果已经到最后一段，最后一个点应当总是在波谷
            if (i === nSegments - 1) {
                nextY = y + amplitude;
            }

            ctx.lineTo(nextX, nextY);

            currentX = nextX;
            currentY = nextY;
        }
        ctx.stroke();
    }

    /**
     * 绘制电话线（使用图片）
     */
    private drawSpiralLine(
        ctx: RenderingContext,
        x: number,
        y: number,
        width: number,
    ) {
        // 使用预加载的图片对象
        if (!this.spiralLineImage) {
            console.warn('电话线图片未加载完成');
            return;
        }

        // 计算图片高度，保持原始宽高比，或者使用固定高度
        const imageHeight = 22; // 固定高度，与线条宽度匹配
        const drawY = y - imageHeight / 2; // 垂直居中

        // 绘制图片
        ctx.drawImage(this.spiralLineImage, x, drawY, width, imageHeight);
    }

    /**
     * 绘制线条
     */
    private drawLine(
        ctx: RenderingContext,
        lineType: LineType,
        x: number,
        y: number,
        width: number,
    ) {
        switch (lineType) {
            case 'straight':
                this.drawStraightLine(ctx, x, y, width);
                break;
            case 'dashed':
                this.drawDashedLine(ctx, x, y, width);
                break;
            case 'wavy':
                this.drawWavyLine(ctx, x, y, width);
                break;
            case 'zigzag':
                this.drawZigzagLine(ctx, x, y, width);
                break;
            case 'spiral':
                this.drawSpiralLine(ctx, x, y, width);
                break;
        }
    }

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

        startY = startY + 25;

        const margin = 40; // 左右边距
        const referenceBlockWidth = 140; // 预览区域色块宽度（加长）
        const referenceBlockHeight = 35; // 预览区域色块高度（缩减）
        const referenceBlockSpacing = 30; // 色块间距
        const textHeight = 30; // 文字高度
        const lineMargin = 15; // 线条距离色块边缘的距离
        const rowSpacing = 15; // 行间距

        // 绘制预览区域（两行：第一行2个，第二行3个）
        const referenceStartY = startY;

        // 第一行：2个色块
        const firstRowWidth = 2 * referenceBlockWidth + referenceBlockSpacing;
        const firstRowStartX =
            margin + (canvasWidth - margin * 2 - firstRowWidth) / 2;

        for (let i = 0; i < 2; i++) {
            const config = lineData.referenceLines[i];
            const blockX =
                firstRowStartX +
                i * (referenceBlockWidth + referenceBlockSpacing);
            const blockY = referenceStartY;

            // 绘制色块（无边框）
            ctx.fillStyle = config.color;
            ctx.fillRect(
                blockX,
                blockY,
                referenceBlockWidth,
                referenceBlockHeight,
            );

            // 绘制线条
            const lineX = blockX + lineMargin;
            const lineY = blockY + referenceBlockHeight / 2;
            const lineWidth = referenceBlockWidth - lineMargin * 2;
            this.drawLine(ctx, config.type, lineX, lineY, lineWidth);

            // 绘制文字标签
            ctx.fillStyle = '#000';
            ctx.font = 'bold 16px "Microsoft Yahei"';
            ctx.textAlign = 'center';
            ctx.textBaseline = 'top';
            ctx.fillText(
                config.name,
                blockX + referenceBlockWidth / 2,
                blockY + referenceBlockHeight + 5,
            );
        }

        // 第二行：3个色块
        const secondRowWidth =
            3 * referenceBlockWidth + 2 * referenceBlockSpacing;
        const secondRowStartX =
            margin + (canvasWidth - margin * 2 - secondRowWidth) / 2;
        const secondRowY =
            referenceStartY + referenceBlockHeight + textHeight + rowSpacing;

        for (let i = 0; i < 3; i++) {
            const config = lineData.referenceLines[i + 2];
            const blockX =
                secondRowStartX +
                i * (referenceBlockWidth + referenceBlockSpacing);
            const blockY = secondRowY;

            // 绘制色块（无边框）
            ctx.fillStyle = config.color;
            ctx.fillRect(
                blockX,
                blockY,
                referenceBlockWidth,
                referenceBlockHeight,
            );

            // 绘制线条
            const lineX = blockX + lineMargin;
            const lineY = blockY + referenceBlockHeight / 2;
            const lineWidth = referenceBlockWidth - lineMargin * 2;
            this.drawLine(ctx, config.type, lineX, lineY, lineWidth);

            // 绘制文字标签
            ctx.fillStyle = '#000';
            ctx.font = 'bold 16px "Microsoft Yahei"';
            ctx.textAlign = 'center';
            ctx.textBaseline = 'top';
            ctx.fillText(
                config.name,
                blockX + referenceBlockWidth / 2,
                blockY + referenceBlockHeight + 5,
            );
        }

        // 绘制虚线分割线
        const dividerY = secondRowY + referenceBlockHeight + textHeight + 30;
        this.drawDashedDivider(dividerY, margin);

        const practiceMargin = 60;
        // 绘制练习区域（2列×8行）
        const practiceStartY = dividerY + 30;
        // 练习区域色块尺寸与预览区域一致
        const practiceBlockWidth = referenceBlockWidth + 50; // 140
        const practiceBlockHeight = referenceBlockHeight + 5; // 35
        const practiceRowHeight = 60; // 每行高度（增加间距，确保不重叠）
        const practiceColWidth = (canvasWidth - practiceMargin * 2 - 30) / 2; // 列宽度（减去列间距）
        const practiceColSpacing = 30; // 列间距

        for (let row = 0; row < 8; row++) {
            for (let col = 0; col < 2; col++) {
                const blockIndex = row * 2 + col;
                const block = lineData.practiceBlocks[blockIndex];
                if (!block) continue;

                // 计算基础位置（考虑错落感）
                const baseX =
                    practiceMargin +
                    col * (practiceColWidth + practiceColSpacing);
                const baseY = practiceStartY + row * practiceRowHeight;

                // 添加随机错落感（限制范围，确保不重叠）
                const blockX = baseX + block.x;
                const blockY = baseY + block.y;

                // 绘制色块（无边框）
                ctx.fillStyle = block.color;
                ctx.fillRect(
                    blockX,
                    blockY,
                    practiceBlockWidth,
                    practiceBlockHeight,
                );
            }
        }
    }
}

export default LineRecognitionDraw;
