import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d';
import { Sprite } from '../sprite';

type CanvasStyle = string | CanvasGradient | CanvasPattern;

export class Text extends Sprite {
    text: string;

    fillStyle?: CanvasStyle = '#fff';
    strokeStyle?: CanvasStyle;
    font?: string = '';
    strokeWidth: number = 1;

    private length: number = 0;
    private descent: number = 0;

    private static measureCanvas = new MotaOffscreenCanvas2D();

    constructor(text: string = '') {
        super();

        this.text = text;
        if (text.length > 0) this.calBox();

        this.renderFn = ({ canvas, ctx }) => {
            ctx.textBaseline = 'bottom';
            ctx.fillStyle = this.fillStyle ?? 'transparent';
            ctx.strokeStyle = this.strokeStyle ?? 'transparent';
            ctx.font = this.font ?? '';
            ctx.lineWidth = this.strokeWidth;

            if (this.strokeStyle) {
                ctx.strokeText(this.text, 0, this.descent);
            }
            if (this.fillStyle) {
                ctx.fillText(this.text, 0, this.descent);
            }
        };
    }

    /**
     * 获取文字的长度
     */
    measure() {
        const ctx = Text.measureCanvas.ctx;
        ctx.textBaseline = 'bottom';
        ctx.font = this.font ?? '';
        const res = ctx.measureText(this.text);
        return res;
    }

    /**
     * 设置显示文字
     * @param text 显示的文字
     */
    setText(text: string) {
        this.text = text;
        this.calBox();
        if (this.parent) this.update(this);
    }

    /**
     * 设置使用的字体
     * @param font 字体
     */
    setFont(font: string) {
        this.font = font;
        this.calBox();
        if (this.parent) this.update(this);
    }

    /**
     * 设置字体样式
     * @param fill 填充样式
     * @param stroke 描边样式
     */
    setStyle(fill?: CanvasStyle, stroke?: CanvasStyle) {
        this.fillStyle = fill;
        this.strokeStyle = stroke;
    }

    /**
     * 设置描边宽度
     * @param width 宽度
     */
    setStrokeWidth(width: number) {
        this.strokeWidth = width;
    }

    /**
     * 计算字体所占空间,从而确定这个元素的大小
     */
    calBox() {
        const { width, fontBoundingBoxAscent } = this.measure();
        this.length = width;
        this.descent = fontBoundingBoxAscent;
        this.size(width, fontBoundingBoxAscent);
    }
}

export type SizedCanvasImageSource = Exclude<
    CanvasImageSource,
    VideoFrame | SVGElement
>;

export class Image extends Sprite {
    image: SizedCanvasImageSource;

    constructor(image: SizedCanvasImageSource) {
        super();
        this.image = image;
        this.size(image.width, image.height);

        this.renderFn = ({ canvas, ctx }) => {
            ctx.drawImage(this.image, 0, 0, canvas.width, canvas.height);
        };
    }

    /**
     * 设置图片资源
     * @param image 图片资源
     */
    setImage(image: SizedCanvasImageSource) {
        this.image = image;
        this.size(image.width, image.height);
        this.update(this);
    }
}