import { PAPER_SIZE } from '../../constants/colors';
import { drawBaseHeader, drawBaseMiniHeader } from './baseHeaderDraw';

/**
 * 基础绘制服务
 * 包含Paper设置和Header绘制功能，可被所有绘制服务复用
 *
 * 提供功能：
 * - Canvas 初始化和配置
 * - Paper 尺寸设置（支持 A4 等标准尺寸）
 * - Header 绘制（支持完整 Header 和迷你 Header）
 * - 分割线绘制
 * - 打印配置管理
 */
export class BaseDrawService {
    headerType: PrintHeader = 'wechat';
    canvas: WechatMiniprogram.Canvas;
    ctx: RenderingContext;
    options: Record<string, any>;
    paperSize: PaperSize;
    currentX: number;
    currentY: number;
    canvasWidth: number; // 逻辑像素宽度
    canvasHeight: number; // 逻辑像素高度

    constructor(
        canvas: Canvas,
        ctx: RenderingContext,
        options?: Record<string, any>,
    ) {
        options = options || {};
        const { appName, appHint } = getApp().getPrintConfig();
        this.canvas = canvas;
        this.ctx = ctx;
        this.paperSize = 'A4';
        this.options = {
            appName,
            appHint,
            title: '看数字，涂一涂',
            subTitle: '找一找下面相同的数字，涂上颜色',

            ...options,
        };
        this.currentX = 0;
        this.currentY = 0;
        this.canvasWidth = 0;
        this.canvasHeight = 0;
        this.setPrintConfig();
    }

    setPrintConfig() {
        const printConfig = getApp().getPrintConfig();
        this.headerType = printConfig.header;
        this.options.appName = printConfig.appName;
    }

    /**
     * 设置Paper（逻辑像素，尺寸除以3）
     */
    setPaper() {
        const { ctx, canvas } = this;
        const { pixelRatio: dpr } = wx.getWindowInfo();
        let { width, height } = PAPER_SIZE[this.paperSize];

        this.canvasWidth = width;
        this.canvasHeight = height;

        // 设置 canvas 为物理像素尺寸（用于高分辨率显示）
        const physicalWidth = width * dpr;
        const physicalHeight = height * dpr;
        canvas.width = physicalWidth;
        canvas.height = physicalHeight;

        // 重置 transform 并 scale 到逻辑像素
        ctx.setTransform(1, 0, 0, 1, 0, 0); // 重置 transform
        ctx.scale(dpr, dpr); // scale 到逻辑像素，后续绘制都使用逻辑像素

        this.clear();
        ctx.fillStyle = '#fff';
        // 使用逻辑像素尺寸填充
        ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
    }

    /**
     * 清除画布
     */
    clear() {
        const canvas = this.canvas;
        this.ctx.clearRect(0, 0, canvas.width, canvas.height);
    }

    /**
     * 绘制Header（逻辑像素，尺寸除以3）
     */
    async drawHeader() {
        this.currentX = 25;
        this.currentY = 25;
        await drawBaseHeader({
            canvas: this.canvas,
            ctx: this.ctx,
            headerType: this.headerType,
            options: {
                appName: this.options.appName || '涂鸦丫小程序',
                appHint: this.options.appHint || '识字|识图|练字|打印',
                title: this.options.title || '看数字，涂一涂',
                subTitle:
                    this.options.subTitle || '找一找下面相同的数字，涂上颜色',
            },
            onHeaderDrawn: (currentY) => {
                this.currentY = currentY;
            },
        });
    }

    /**
     * 绘制迷你Header（逻辑像素，尺寸除以3）
     */
    drawMiniHeader() {
        drawBaseMiniHeader({
            ctx: this.ctx,
            canvasWidth: this.canvasWidth,
            options: {
                appName: this.options.appName || '涂鸦丫小程序',
                title: this.options.title || '看数字，涂一涂',
            },
            onHeaderDrawn: (currentY) => {
                console.log('drawMiniHeader currentY', currentY);
                this.currentY = currentY;
            },
        });
    }

    /**
     * 绘制分割线（逻辑像素，尺寸除以3）
     */
    drawDivider() {
        const { ctx, canvasWidth } = this;
        const dividerY = this.currentY;

        ctx.strokeStyle = '#000';
        ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.moveTo(24, dividerY);
        ctx.lineTo(canvasWidth - 24, dividerY);
        ctx.stroke();

        this.currentY = dividerY + 10; // 分割线下方10px间距
    }

    /**
     * 绘制虚线分割线（逻辑像素，尺寸除以3）
     * @param y 分割线的Y坐标
     * @param margin 左右边距，默认为40
     * @param color 线条颜色，默认为'#999'
     * @param lineWidth 线条宽度，默认为1
     */
    drawDashedDivider(
        y: number,
        margin: number = 40,
        color: string = '#999',
        lineWidth: number = 1,
    ) {
        const { ctx, canvasWidth } = this;

        ctx.strokeStyle = color;
        ctx.lineWidth = lineWidth;
        ctx.setLineDash([4, 4]); // 虚线
        ctx.beginPath();
        ctx.moveTo(margin, y);
        ctx.lineTo(canvasWidth - margin, y);
        ctx.stroke();
        ctx.setLineDash([]); // 重置为实线
    }

    /**
     * 绘制线条（逻辑像素，尺寸除以3）
     * @param x1 起点X坐标
     * @param y1 起点Y坐标
     * @param x2 终点X坐标
     * @param y2 终点Y坐标
     * @param options 可选参数
     * @param options.isDashed 是否为虚线，默认为true（虚线）
     * @param options.dashPattern 虚线模式，默认为[4, 4]
     * @param options.color 线条颜色，默认为'#999'
     * @param options.lineWidth 线条宽度，默认为1
     */
    drawLine(
        x1: number,
        y1: number,
        x2: number,
        y2: number,
        options?: {
            isDashed?: boolean;
            dashPattern?: number[];
            color?: string;
            lineWidth?: number;
        },
    ): void {
        const { ctx } = this;
        const {
            isDashed = true,
            dashPattern = [4, 4],
            color = '#999',
            lineWidth = 1,
        } = options || {};

        ctx.strokeStyle = color;
        ctx.lineWidth = lineWidth;

        // 设置虚线或实线
        if (isDashed) {
            ctx.setLineDash(dashPattern);
        } else {
            ctx.setLineDash([]);
        }

        // 绘制线条
        ctx.beginPath();
        ctx.moveTo(x1, y1);
        ctx.lineTo(x2, y2);
        ctx.stroke();

        // 重置为实线（避免影响后续绘制）
        ctx.setLineDash([]);
    }

    /**
     * 绘制网格线（逻辑像素，尺寸除以3）
     * @param gridStartX 网格起始X坐标
     * @param gridStartY 网格起始Y坐标
     * @param cellWidth 每个格子的宽度
     * @param cellHeight 每个格子的高度
     * @param cols 列数
     * @param rows 行数
     */
    drawGridLines(
        gridStartX: number,
        gridStartY: number,
        cellWidth: number,
        cellHeight: number,
        cols: number,
        rows: number,
    ): void {
        const { ctx } = this;

        // 在函数内部计算网格总宽度和高度
        const gridWidth = cellWidth * cols;
        const gridHeight = cellHeight * rows;

        ctx.strokeStyle = '#000';
        ctx.lineWidth = 1;
        ctx.setLineDash([]); // 实线

        // 绘制垂直线
        for (let i = 0; i <= cols; i++) {
            const x = gridStartX + i * cellWidth;
            ctx.beginPath();
            ctx.moveTo(x, gridStartY);
            ctx.lineTo(x, gridStartY + gridHeight);
            ctx.stroke();
        }

        // 绘制水平线
        for (let i = 0; i <= rows; i++) {
            const y = gridStartY + i * cellHeight;
            ctx.beginPath();
            ctx.moveTo(gridStartX, y);
            ctx.lineTo(gridStartX + gridWidth, y);
            ctx.stroke();
        }
    }

    /**
     * 绘制圆角矩形框（逻辑像素，尺寸除以3）
     * @param x 框的X坐标
     * @param y 框的Y坐标
     * @param width 框的宽度
     * @param height 框的高度
     * @param options 可选参数
     * @param options.isDashed 是否为虚线，默认为false（实线）
     * @param options.radius 圆角半径，默认为10
     * @param options.color 线条颜色，默认为'#000'
     * @param options.lineWidth 线条宽度，默认为1
     */
    drawRoundedRect(
        x: number,
        y: number,
        width: number,
        height: number,
        options?: {
            isDashed?: boolean;
            radius?: number;
            color?: string;
            lineWidth?: number;
        },
    ): void {
        const { ctx } = this;
        const {
            isDashed = false,
            radius = 10,
            color = '#000',
            lineWidth = 1,
        } = options || {};

        ctx.strokeStyle = color;
        ctx.lineWidth = lineWidth;

        // 设置虚线或实线
        if (isDashed) {
            ctx.setLineDash([4, 4]); // 虚线
        } else {
            ctx.setLineDash([]); // 实线
        }

        // 绘制圆角矩形
        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();
        ctx.stroke();

        // 重置为实线（避免影响后续绘制）
        ctx.setLineDash([]);
    }

    /**
     * 绘制符号（使用路径绘制）
     * @param x 符号中心X坐标
     * @param y 符号中心Y坐标
     * @param symbol 符号类型：'+', '-', '=', '×', '✓'
     * @param size 符号大小
     */
    drawSymbol(x: number, y: number, symbol: string, size: number): void {
        const { ctx } = this;
        ctx.save();
        ctx.translate(x, y);

        const lineWidth = size * 0.15; // 线条宽度
        const halfSize = size / 2;
        const strokeLength = halfSize * 0.7; // 线条长度

        ctx.strokeStyle = '#000';
        ctx.lineWidth = lineWidth;
        ctx.lineCap = 'round';
        ctx.lineJoin = 'round';

        switch (symbol) {
            case '+':
                // 加号：横线和竖线
                ctx.beginPath();
                // 横线
                ctx.moveTo(-strokeLength, 0);
                ctx.lineTo(strokeLength, 0);
                // 竖线
                ctx.moveTo(0, -strokeLength);
                ctx.lineTo(0, strokeLength);
                ctx.stroke();
                break;

            case '-':
                // 减号：横线
                ctx.beginPath();
                ctx.moveTo(-strokeLength, 0);
                ctx.lineTo(strokeLength, 0);
                ctx.stroke();
                break;

            case '=':
                // 等号：两条横线
                const equalsSpacing = size * 0.15; // 两条线之间的间距
                ctx.beginPath();
                // 上横线
                ctx.moveTo(-strokeLength, -equalsSpacing);
                ctx.lineTo(strokeLength, -equalsSpacing);
                // 下横线
                ctx.moveTo(-strokeLength, equalsSpacing);
                ctx.lineTo(strokeLength, equalsSpacing);
                ctx.stroke();
                break;

            case '×':
                // 乘号：两条斜线
                ctx.beginPath();
                // 左上到右下
                ctx.moveTo(-strokeLength * 0.7, -strokeLength * 0.7);
                ctx.lineTo(strokeLength * 0.7, strokeLength * 0.7);
                // 右上到左下
                ctx.moveTo(strokeLength * 0.7, -strokeLength * 0.7);
                ctx.lineTo(-strokeLength * 0.7, strokeLength * 0.7);
                ctx.stroke();
                break;

            case '✓':
                // 对号：勾，整体更大，右侧的线更长
                const checkScale = 1.2; // 对号整体放大1.2倍
                ctx.beginPath();
                const checkStartX = -strokeLength * 0.5 * checkScale;
                const checkStartY = -strokeLength * 0.2 * checkScale;
                const checkMidX = -strokeLength * 0.1 * checkScale;
                const checkMidY = strokeLength * 0.3 * checkScale;
                const checkEndX = strokeLength * 1.0 * checkScale; // 增加右侧长度
                const checkEndY = -strokeLength * 0.4 * checkScale; // 稍微向上调整
                ctx.moveTo(checkStartX, checkStartY);
                ctx.lineTo(checkMidX, checkMidY);
                ctx.lineTo(checkEndX, checkEndY);
                ctx.stroke();
                break;

            default:
                // 默认绘制加号
                ctx.beginPath();
                ctx.moveTo(-strokeLength, 0);
                ctx.lineTo(strokeLength, 0);
                ctx.moveTo(0, -strokeLength);
                ctx.lineTo(0, strokeLength);
                ctx.stroke();
        }

        ctx.restore();
    }

    /**
     * 绘制圆点
     * @param ctx 绘制上下文
     * @param x 圆点中心X坐标
     * @param y 圆点中心Y坐标
     * @param radius 圆点半径
     * @param fillColor 填充颜色，默认为 '#93D333'
     * @param strokeColor 边线颜色，如果传入则绘制边线，宽度为1，默认不绘制
     */
    drawDot(
        ctx: RenderingContext,
        x: number,
        y: number,
        radius: number,
        fillColor?: string,
        strokeColor?: string,
    ) {
        ctx.beginPath();
        ctx.arc(x, y, radius, 0, Math.PI * 2);

        // 绘制填充
        ctx.fillStyle = fillColor ?? '#93D333';
        ctx.fill();

        // 绘制边线（如果提供了边线颜色）
        if (strokeColor) {
            ctx.strokeStyle = strokeColor;
            ctx.lineWidth = 1;
            ctx.stroke();
        }
    }

    /**
     * 准备绘制（公共初始化逻辑）
     * 执行：setPrintConfig -> clear -> setPaper
     * 子类可以在调用此方法前后执行自定义逻辑（如数据验证、异步资源加载等）
     */
    prepareDraw() {
        this.setPrintConfig();
        this.clear();
        this.setPaper();
    }

    /**
     * 绘制 Header 和 Divider（公共绘制逻辑）
     * 根据 headerType 自动选择绘制完整 Header 或迷你 Header，然后绘制分割线
     */
    async drawHeaderAndDivider() {
        // 绘制Header
        if (this.headerType !== 'minimal') {
            await this.drawHeader();
        } else {
            this.drawMiniHeader();
        }

        // 绘制内容区域分割线
        this.drawDivider();
    }

    /**
     * 绘制空白方框（边框1px，#999，无填充，不显示数字）
     */
    drawBox(
        ctx: RenderingContext,
        x: number,
        y: number,
        width: number,
        height: number,
        color: string = '#999',
        lineWidth: number = 1,
    ) {
        // 绘制方框边框（1px，#999，无填充）
        ctx.strokeStyle = color;
        ctx.lineWidth = lineWidth;
        ctx.setLineDash([]);
        ctx.strokeRect(x, y, width, height);
    }

    /**
     * 绘制正方形方框（调用drawBox，减少参数）
     * @param ctx 渲染上下文
     * @param x 方框左上角x
     * @param y 方框左上角y
     * @param size 方框边长
     * @param color 边框颜色（可选，默认为#999）
     * @param lineWidth 线宽（可选，默认为1）
     */
    drawSquareBox(
        ctx: RenderingContext,
        x: number,
        y: number,
        size: number,
        color: string = '#999',
        lineWidth: number = 1,
    ) {
        this.drawBox(ctx, x, y, size, size, color, lineWidth);
    }
}
