import { BaseDrawService } from '../core/draw/baseDraw';
import { CharacterItem } from '../types/characterType';

/**
 * cnchar-data 坐标系配置
 * 参考 hanzi-writer 的实现逻辑
 * 字符数据的边界框：左上角 (0, -124)，右下角 (1024, 900)
 */
const CHAR_BOUNDS = {
    minX: 0,
    minY: -124,
    maxX: 1024,
    maxY: 900,
};
const CHAR_WIDTH = CHAR_BOUNDS.maxX - CHAR_BOUNDS.minX; // 1024
const CHAR_HEIGHT = CHAR_BOUNDS.maxY - CHAR_BOUNDS.minY; // 1024

/**
 * 计算缩放变换参数（模仿 cnchar.draw 的 getScalingTransform 函数）
 * 用于将 1024x1024 坐标系的字符数据变换到目标画布尺寸
 */
interface ScalingTransform {
    xOffset: number;
    yOffset: number;
    scale: number;
}

function getScalingTransform(
    width: number,
    height: number,
    padding: number,
): ScalingTransform {
    // 计算可用空间
    const availableWidth = width - 2 * padding;
    const availableHeight = height - 2 * padding;

    // 计算缩放比例（取较小的比例以确保字符完整显示）
    const scaleX = availableWidth / CHAR_WIDTH;
    const scaleY = availableHeight / CHAR_HEIGHT;
    const scale = Math.min(scaleX, scaleY);

    // 计算偏移量（居中显示）
    const scaledWidth = CHAR_WIDTH * scale;
    const scaledHeight = CHAR_HEIGHT * scale;
    const centerX = padding + (availableWidth - scaledWidth) / 2;
    const centerY = padding + (availableHeight - scaledHeight) / 2;

    // 计算 xOffset 和 yOffset（考虑字符边界框的偏移）
    const xOffset = -CHAR_BOUNDS.minX * scale + centerX;
    const yOffset = -CHAR_BOUNDS.minY * scale + centerY;

    return { xOffset, yOffset, scale };
}

/**
 * SVG 路径解析与绘制（支持 M/L/Q/Z 命令）
 * 参考 cnchar.draw 的实现，使用 Canvas transform 进行坐标变换
 */
interface DrawSvgPathParams {
    ctx: RenderingContext;
    pathD: string;
}

function drawSvgPath({ ctx, pathD }: DrawSvgPathParams) {
    // 使用正则表达式匹配 SVG 路径命令
    // 支持 M（moveTo）、L（lineTo）、Q（二次贝塞尔曲线）、Z（closePath）
    const commandRegex = /([MLQZ])([^MLQZ]*?)(?=[MLQZ]|$)/gi;
    const commands: Array<{ cmd: string; coords: string }> = [];

    let match;
    while ((match = commandRegex.exec(pathD)) !== null) {
        const cmd = match[1].toUpperCase();
        const coords = match[2].trim();
        commands.push({ cmd, coords });
    }

    // 解析坐标的辅助函数
    const parseCoords = (coords: string): number[] => {
        return coords
            .split(/[\s,]+/)
            .filter((part) => part.trim() !== '')
            .map((part) => parseFloat(part));
    };

    for (const { cmd, coords } of commands) {
        const coordValues = parseCoords(coords);

        switch (cmd) {
            case 'M':
                if (coordValues.length >= 2) {
                    ctx.moveTo(coordValues[0], coordValues[1]);
                }
                break;
            case 'L':
                if (coordValues.length >= 2) {
                    ctx.lineTo(coordValues[0], coordValues[1]);
                }
                break;
            case 'Q':
                // 二次贝塞尔曲线：Q cpx cpy x y
                if (coordValues.length >= 4) {
                    ctx.quadraticCurveTo(
                        coordValues[0],
                        coordValues[1],
                        coordValues[2],
                        coordValues[3],
                    );
                }
                break;
            case 'Z':
                ctx.closePath();
                break;
            default:
                console.warn(`未知的 SVG 路径命令: ${cmd}`);
        }
    }
}

interface DrawStrokesParams {
    ctx: RenderingContext;
    strokes: string[];
    offsetX: number;
    offsetY: number;
    size: number;
    uptoInclusive: number;
    fillStyle: string;
    strokeStyle: string;
    lineWidth: number;
}

/**
 * 绘制笔画（参考 cnchar.draw 的实现方式）
 * 使用 Canvas transform 进行坐标变换，支持 1024x1024 坐标系
 */
function drawStrokes({
    ctx,
    strokes,
    offsetX,
    offsetY,
    size,
    uptoInclusive,
    fillStyle,
    strokeStyle: _strokeStyle, // 保留接口兼容性，cnchar 模式只使用 fill
    lineWidth: _lineWidth, // 保留接口兼容性，cnchar 模式只使用 fill
}: DrawStrokesParams) {
    // 抑制未使用变量警告
    void _strokeStyle;
    void _lineWidth;
    // 设置 Canvas 绘制质量
    ctx.imageSmoothingEnabled = true;
    ctx.imageSmoothingQuality = 'high';

    // 设置路径绘制属性
    ctx.lineCap = 'round';
    ctx.lineJoin = 'round';
    ctx.miterLimit = 10;

    // 添加内边距：在田字格四周预留空间，避免笔画贴边
    const padding = size * 0.1;

    // 计算缩放变换参数（参考 cnchar.draw 的 getScalingTransform）
    const transform = getScalingTransform(size, size, padding);

    for (let s = 0; s <= uptoInclusive && s < strokes.length; s++) {
        ctx.save();

        // 应用变换矩阵（参考 cnchar.draw 的方式）
        // 1. 先平移到目标位置
        // 2. 再应用 Y 轴翻转和缩放
        // transform: translate(xOffset, height - yOffset) scale(scale, -scale)
        ctx.translate(
            offsetX + transform.xOffset,
            offsetY + size - transform.yOffset,
        );
        ctx.scale(transform.scale, -transform.scale);

        // 绘制路径
        ctx.beginPath();
        drawSvgPath({ ctx, pathD: strokes[s] });

        // 使用 fill 绘制（cnchar 只使用 fill）
        ctx.fillStyle = fillStyle;
        ctx.fill();

        ctx.restore();
    }
}

interface DrawTianZiGridParams {
    ctx: RenderingContext;
    x: number;
    y: number;
    size: number;
    lineColor?: string;
    boldColor?: string;
}

function drawTianZiGrid({
    ctx,
    x,
    y,
    size,
    lineColor = '#a8d5a8', // 浅绿色（中线）
    boldColor = '#7fb069', // 中等绿色（外框）
}: DrawTianZiGridParams) {
    // 外框（逻辑像素）- 使用中等绿色，清晰可见
    ctx.strokeStyle = boldColor;
    ctx.lineWidth = 1; // 2/3≈1，逻辑像素
    ctx.strokeRect(x - size / 2, y - size / 2, size, size);

    // 中线（逻辑像素）- 使用浅绿色，柔和护眼
    ctx.strokeStyle = lineColor;
    ctx.lineWidth = 1; // 逻辑像素
    ctx.beginPath();
    // 竖线
    ctx.moveTo(x, y - size / 2);
    ctx.lineTo(x, y + size / 2);
    // 横线
    ctx.moveTo(x - size / 2, y);
    ctx.lineTo(x + size / 2, y);
    ctx.stroke();
    ctx.closePath();

    // 对角线（淡绿色，逻辑像素）- 使用很淡的绿色，提供辅助参考线
    ctx.strokeStyle = '#d4f0d4'; // 很淡的绿色
    ctx.lineWidth = 1;
    ctx.beginPath();
    ctx.moveTo(x - size / 2, y - size / 2);
    ctx.lineTo(x + size / 2, y + size / 2);
    ctx.moveTo(x + size / 2, y - size / 2);
    ctx.lineTo(x - size / 2, y + size / 2);
    ctx.stroke();
    ctx.closePath();
}

class WordDrawService extends BaseDrawService {
    constructor(
        canvas: Canvas,
        ctx: RenderingContext,
        options?: Record<string, any>,
    ) {
        options = options || {};
        super(canvas, ctx, {
            title: '田字格  练 字 贴',
            subTitle: '按笔画临摹练习',
            ...options,
        });
    }

    /**
     * 绘制页眉和基础布局
     */
    async drawLayout() {
        this.setPrintConfig();
        this.clear();
        this.setPaper();

        // 绘制Header
        if (this.headerType !== 'minimal') {
            await this.drawHeader();
        } else {
            this.drawMiniHeader();
        }

        this.drawDivider();
        this.drawContentEmpty();
    }

    async drawContentEmpty() {
        this.clearContentArea();
        this.drawContent(null);
    }

    /**
     * 绘制田字格和练字内容
     * @param wordsMap 形如 { "其": ["M.. L.. Z", ...], ... }，不超过 10 个汉字
     */
    drawPracticeContent(characters: CharacterItem[]) {
        // 清空内容区域（页眉以下的部分）
        this.clearContentArea();

        // 绘制田字格和练字内容
        this.drawContent(characters);
    }

    /**
     * 清空内容区域（页眉以下的部分）
     */
    private clearContentArea() {
        const { ctx } = this;
        const contentStartY = this.currentY;

        // 清空页眉以下的所有内容（使用逻辑像素）
        ctx.fillStyle = '#fff';
        ctx.fillRect(
            0,
            contentStartY,
            this.canvasWidth,
            this.canvasHeight - contentStartY,
        );
    }

    /**
     * 绘制正文内容：两阶段绘制 - 先绘制空田字格，再绘制练字内容
     */
    /**
     * 绘制正文内容：包括田字格的排布和内容
     *
     * minGap 作用解释：
     *    minGap（最小列间距）用于田字格水平方向（每一行格子之间的间距）的初始最小值。它保证多个田字格在一行内不会紧贴排布、而是有一个最小的间隔，整体看起来不会拥挤。后续还会结合画布实际剩余空间动态调整为更合适的实际间距 actualColGap。
     *
     * rowGap 作用解释：
     *    rowGap（行间距）用于田字格竖直方向（每一行田字格之间的间隔）的初始最小值。它防止行与行的田字格上下贴得太紧，增加一定的可视呼吸空间。之后同样会结合剩余空间动态调整为实际间距 actualRowGap。
     */
    drawContent(characterData: CharacterItem[] | null) {
        const { ctx } = this;

        // 布局参数（逻辑像素，原始尺寸除以3）
        const topGap = 17; // 50/3≈17
        const leftMargin = 40; // 120/3=40
        const rightMargin = 40; // 120/3=40
        const bottomMargin = 40; // 120/3=40
        const contentTop = this.currentY + topGap;
        const contentWidth = this.canvasWidth - leftMargin - rightMargin;
        const contentHeight = this.canvasHeight - contentTop - bottomMargin;

        const cellSize = 47; // 140/3≈47
        // 统一通过 getMaxGridLayout 获取最大行列数
        const { maxRow, maxCol } = this.getMaxGridLayout();

        // 动态调整间距以充分利用空间（在允许的最小间距基础上弹性扩展以适配画布）
        const actualRowGap =
            maxRow > 1 ? (contentHeight - maxRow * cellSize) / (maxRow - 1) : 0;
        const actualColGap =
            maxCol > 1 ? (contentWidth - maxCol * cellSize) / (maxCol - 1) : 0;

        // console.log(`布局信息: 行数=${rowNumber}, 列数=${columnNumber}, 行间距=${actualRowGap.toFixed(1)}, 列间距=${actualColGap.toFixed(1)}`);

        // 第一阶段：绘制所有空田字格
        this.drawEmptyGrids({
            ctx,
            startX: leftMargin,
            startY: contentTop,
            cellSize,
            colGap: actualColGap,
            rowGap: actualRowGap,
            maxRow,
            maxCol,
        });

        if (characterData && characterData.length > 0) {
            // 第二阶段：绘制练字内容
            this.drawPracticeContentInternal({
                ctx,
                characterData,
                startX: leftMargin,
                startY: contentTop,
                cellSize,
                colGap: actualColGap,
                rowGap: actualRowGap,
                maxCol,
                maxRow,
            });
        }
    }

    /**
     * 获取当前页面可绘制田字格的最大行数与列数（与绘制使用同一套计算规则）
     */
    getMaxGridLayout(): { maxRow: number; maxCol: number } {
        // 布局参数需与 drawContent 保持一致（逻辑像素）
        const topGap = 17; // 50/3≈17
        const leftMargin = 40; // 120/3=40
        const rightMargin = 40; // 120/3=40
        const bottomMargin = 40; // 120/3=40
        const contentTop = this.currentY + topGap;
        const contentWidth = this.canvasWidth - leftMargin - rightMargin;
        const contentHeight = this.canvasHeight - contentTop - bottomMargin;

        const cellSize = 47; // 140/3≈47
        const minGap = 8; // 24/3=8
        const rowGap = 12; // 36/3=12

        const maxCol = Math.max(
            1,
            Math.floor((contentWidth + minGap) / (cellSize + minGap)),
        );
        const maxRow = Math.max(
            1,
            Math.floor((contentHeight + rowGap) / (cellSize + rowGap)),
        );

        return { maxRow, maxCol };
    }

    /**
     * 绘制空田字格网格
     */
    drawEmptyGrids({
        ctx,
        startX,
        startY,
        cellSize,
        colGap,
        rowGap,
        maxRow,
        maxCol,
    }: {
        ctx: RenderingContext;
        startX: number;
        startY: number;
        cellSize: number;
        colGap: number;
        rowGap: number;
        maxRow: number; // 行数
        maxCol: number; // 列数
    }) {
        for (let row = 0; row < maxRow; row++) {
            for (let col = 0; col < maxCol; col++) {
                const x = startX + col * (cellSize + colGap) + cellSize / 2;
                const y = startY + row * (cellSize + rowGap) + cellSize / 2;
                drawTianZiGrid({ ctx, x, y, size: cellSize });
            }
        }
    }

    /**
     * 绘制练字内容（参考 template.html 的实现）
     */
    drawPracticeContentInternal({
        ctx,
        characterData,
        startX,
        startY,
        cellSize,
        colGap,
        rowGap,
        maxCol,
        maxRow,
    }: {
        ctx: RenderingContext;
        characterData: CharacterItem[];
        startX: number;
        startY: number;
        cellSize: number;
        colGap: number;
        rowGap: number;
        maxCol: number;
        maxRow: number;
    }) {
        let rowIndex = 0;

        for (let i = 0; i < characterData.length; i++) {
            const item = characterData[i];
            const strokes = item.strokes;
            const strokeCount = strokes.length;

            const totalCells = 1 + strokeCount; // 预览 + 练习
            const totalRows = Math.ceil(totalCells / maxCol);

            if (rowIndex + totalRows > maxRow) {
                break; // 放不下，停止绘制
            }

            for (let cellIdx = 0; cellIdx < totalCells; cellIdx++) {
                const localRowOffset = Math.floor(cellIdx / maxCol);
                const localColIndex = cellIdx % maxCol;
                const globalRow = rowIndex + localRowOffset;
                if (globalRow >= maxRow) {
                    break;
                }
                if (cellIdx === 0) {
                    this.drawPreviewCell({
                        ctx,
                        strokes,
                        startX,
                        startY,
                        cellSize,
                        colGap,
                        rowGap,
                        rowIndex: globalRow,
                    });
                } else {
                    const strokeIndex = cellIdx - 1;
                    this.drawPracticeCell({
                        ctx,
                        strokes,
                        strokeIndex,
                        startX,
                        startY,
                        cellSize,
                        colGap,
                        rowGap,
                        rowIndex: globalRow,
                        columnIndex: localColIndex,
                    });
                }
            }

            rowIndex = rowIndex + totalRows;
        }
    }

    /**
     * 绘制预览格（完整汉字）
     */
    drawPreviewCell({
        ctx,
        strokes,
        startX,
        startY,
        cellSize,
        colGap,
        rowGap,
        rowIndex,
    }: {
        ctx: RenderingContext;
        strokes: string[];
        startX: number;
        startY: number;
        cellSize: number;
        colGap: number;
        rowGap: number;
        rowIndex: number;
    }) {
        const columnIndex = 0;
        const x = startX + columnIndex * (cellSize + colGap);
        const y = startY + rowIndex * (cellSize + rowGap);

        // console.log(`预览格 [${rowIndex}, ${columnIndex}] 坐标: (${x}, ${y}), 笔画数: ${strokes.length}`);

        // 绘制完整汉字（深灰色，Fill + Stroke模式）
        // 参考一般练字贴：预览字使用深灰色，不是纯黑色，更柔和护眼
        drawStrokes({
            ctx,
            strokes,
            offsetX: x,
            offsetY: y,
            size: cellSize,
            uptoInclusive: strokes.length - 1,
            fillStyle: 'rgb(85,85,85)', // 深灰色填充（#555555），比#666666更深一点
            strokeStyle: 'rgb(85,85,85)', // 深灰色描边
            lineWidth: 1.2, // Fill + Stroke 模式，线条宽度调小一点（逻辑像素）
        });
    }

    /**
     * 绘制练习格（逐笔画）
     */
    drawPracticeCell({
        ctx,
        strokes,
        strokeIndex,
        startX,
        startY,
        cellSize,
        colGap,
        rowGap,
        rowIndex,
        columnIndex,
    }: {
        ctx: RenderingContext;
        strokes: string[];
        strokeIndex: number;
        startX: number;
        startY: number;
        cellSize: number;
        colGap: number;
        rowGap: number;
        rowIndex: number;
        columnIndex: number;
    }) {
        const x = startX + columnIndex * (cellSize + colGap);
        const y = startY + rowIndex * (cellSize + rowGap);

        // console.log(`练习格 [${rowIndex}, ${columnIndex}] 坐标: (${x}, ${y}), 笔画: ${strokeIndex + 1}/${strokes.length}`);

        // 绘制到指定笔画的汉字（浅灰色，Fill + Stroke模式）
        // 参考一般练字贴：练习字使用浅灰色，便于临摹
        drawStrokes({
            ctx,
            strokes,
            offsetX: x,
            offsetY: y,
            size: cellSize,
            uptoInclusive: strokeIndex,
            fillStyle: 'rgb(170,170,170)', // 浅灰色填充（#aaaaaa），参考练字贴颜色
            strokeStyle: 'rgb(170,170,170)', // 浅灰色描边
            lineWidth: 1.2, // Fill + Stroke 模式，线条宽度调小一点（逻辑像素）
        });
    }

    // drawDivider 已在基类中实现，此方法保留以保持兼容
    drawDivider() {
        super.drawDivider();
    }
}

export default WordDrawService;
