import EventEmitter from "@/utils/emitter";

/**
 * Canvas绘图类，支持多种图形绘制和多人同步
 * 使用百分比坐标系统确保跨设备一致性
 */
class Canvas extends EventEmitter {
    constructor(canvasId) {
        super();
        this.canvas = document.getElementById(canvasId);
        if (!this.canvas) {
            throw new Error(`Canvas element with id ${canvasId} not found`);
        }

        this.ctx = this.canvas.getContext('2d');
        this.shapes = []; // 所有已绘制形状
        this.currentShape = null; // 当前正在绘制的形状
        this.isDrawing = false; 
        this.drawingTool = 'pencil'; 
        this.pathOptimizationEnabled = true; 
        this.optimizationThreshold = 0.005; 
        this.currentColor = '#ffcc00';
        this.currentThickness = 2;

        this.resize();

        // 绑定事件
        this.handleMouseDown = this.handleMouseDown.bind(this);
        this.handleMouseMove = this.handleMouseMove.bind(this);
        this.handleMouseUp = this.handleMouseUp.bind(this);
        this.handleMouseLeave = this.handleMouseLeave.bind(this);

        this.canvas.addEventListener('mousedown', this.handleMouseDown);
        this.canvas.addEventListener('mousemove', this.handleMouseMove);
        this.canvas.addEventListener('mouseup', this.handleMouseUp);
        this.canvas.addEventListener('mouseleave', this.handleMouseLeave);

        window.addEventListener('resize', () => this.resize());
    }

    resize() {
        const parent = this.canvas.parentElement;
        if (!parent) return;

        const containerWidth = parent.offsetWidth;
        const containerHeight = parent.offsetHeight;

        let width = containerWidth;
        let height = Math.floor((width * 9) / 16);

        if (height > containerHeight) {
            height = containerHeight;
            width = Math.floor((height * 16) / 9);
        }

        if (this.canvas.width === width && this.canvas.height === height) return;

        this.canvas.width = width;
        this.canvas.height = height;
        this.canvas.style.width = width + "px";
        this.canvas.style.height = height + "px";

        this.render();
    }

    setDrawingTool(tool) { this.drawingTool = tool; }
    setColor(color) { this.currentColor = color; }
    setThickness(size) { this.currentThickness = size; }
    setPathOptimization(enabled) { this.pathOptimizationEnabled = enabled; }
    setOptimizationThreshold(threshold) { this.optimizationThreshold = threshold; }
    getShapes() { return this.shapes; }
    setShapes(shapes) { this.shapes = shapes; this.render(); }

    getMouseCoordinates(e) {
        const rect = this.canvas.getBoundingClientRect();
        return {
            x: (e.clientX - rect.left) / this.canvas.width,
            y: (e.clientY - rect.top) / this.canvas.height
        };
    }

    handleMouseDown(e) {
        this.isDrawing = true;
        const coords = this.getMouseCoordinates(e);

        if (this.drawingTool === 'pencil') {
            this.currentShape = { type: 'pencil', data: { color: this.currentColor, path: [coords], thickness: this.currentThickness } };
        } else if (this.drawingTool === 'line') {
            this.currentShape = { type: 'line', data: { color: this.currentColor, start: coords, end: coords, thickness: this.currentThickness } };
        } else if (this.drawingTool === 'rectangle') {
            this.currentShape = { type: 'rectangle', data: { color: this.currentColor, start: coords, end: coords, thickness: this.currentThickness, fill: false } };
        } else if (this.drawingTool === 'circle') {
            this.currentShape = { type: 'circle', data: { color: this.currentColor, start: coords, end: coords, thickness: this.currentThickness, fill: false } };
        } else if (this.drawingTool === 'eraser') {
            this.currentShape = { type: 'eraser', data: { color: '#ffffff', start: coords, end: coords, thickness: 3 } };
        }

        this.emit('drawingStart', this.currentShape);
    }

    handleMouseMove(e) {
        if (!this.isDrawing || !this.currentShape) return;
        const coords = this.getMouseCoordinates(e);

        if (this.drawingTool === 'pencil') {
            this.currentShape.data.path.push(coords);
        } else {
            this.currentShape.data.end = coords;
        }

        this.render();
        this.emit('drawingUpdate', this.currentShape);
    }

    handleMouseUp(e) { 
        if (!this.isDrawing || !this.currentShape) return;
        this.isDrawing = false;
        const coords = this.getMouseCoordinates(e);
        if (this.drawingTool === 'pencil' && this.pathOptimizationEnabled && this.currentShape.data.path.length > 10) {
            this.currentShape.data.path = this.optimizePath(this.currentShape.data.path);
        } else {
            this.currentShape.data.end = coords;
        }

        this.shapes.push({ ...this.currentShape });
        this.emit('drawingEnd', this.currentShape);
        this.currentShape = null;
        this.render();
    }

    handleMouseLeave(e) {
        if (this.isDrawing) this.handleMouseUp(e);
    }

    optimizePath(path) {
        if (path.length < 3) return path;
        const optimizedPath = [path[0]];
        for (let i = 1; i < path.length - 1;) {
            let a = 1;
            while (i + a < path.length && this.calculateDistance(path[i], path[i + a]) < this.optimizationThreshold) a++;
            optimizedPath.push(path[i]);
            i += a;
        }
        optimizedPath.push(path[path.length - 1]);
        return optimizedPath;
    }

    calculateDistance(p1, p2) {
        return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
    }

    addShape(shapeData) {
        if (Array.isArray(shapeData)) this.shapes.push(...shapeData);
        else this.shapes.push(shapeData);
        this.render();
    }

    clearCanvas() {
        this.shapes = [];
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
        this.emit('clear');
    }

    exportToDataURL(type = 'image/png', quality = 1) {
        return this.canvas.toDataURL(type, quality);
    }

    render() {
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);

        // 绘制历史形状
        this.shapes.forEach(shape => this.drawShape(shape));

        // 绘制当前正在绘制的形状
        if (this.currentShape) this.drawShape(this.currentShape);

        // 画画布边框
        this.ctx.save();
        this.ctx.strokeStyle = "#000";
        this.ctx.lineWidth = 2;
        this.ctx.strokeRect(0, 0, this.canvas.width, this.canvas.height);
        this.ctx.restore();
    }

    drawShape(shape) {
        switch (shape.type) {
            case 'pencil': this.drawPencil(shape.data); break;
            case 'line': this.drawLine(shape.data); break;
            case 'rectangle': this.drawRectangle(shape.data); break;
            case 'circle': this.drawCircle(shape.data); break;
            case 'eraser': this.drawEraser(shape.data, shape); break;
        }
    }

    drawPencil(p) {
        if (p.path.length < 2) return;
        const path = p.path.map(pt => ({ x: pt.x * this.canvas.width, y: pt.y * this.canvas.height }));
        this.ctx.beginPath();
        this.ctx.strokeStyle = p.color;
        this.ctx.lineWidth = p.thickness;
        this.ctx.lineCap = 'round';
        this.ctx.lineJoin = 'round';
        this.drawSmoothCurve(this.ctx, path);
        this.ctx.stroke();
    }

    drawSmoothCurve(ctx, path) {
        if (path.length < 3) { ctx.moveTo(path[0].x, path[0].y); for (let i = 1; i < path.length; i++) ctx.lineTo(path[i].x, path[i].y); return; }
        ctx.moveTo(path[0].x, path[0].y);
        const threshold = 5;
        for (let i = 1; i < path.length - 2;) {
            let a = 1;
            while (i + a < path.length - 2 &&
                Math.sqrt(Math.pow(path[i].x - path[i + a].x, 2) + Math.pow(path[i].y - path[i + a].y, 2)) < threshold) a++;
            const xc = (path[i].x + path[i + a].x) / 2;
            const yc = (path[i].y + path[i + a].y) / 2;
            ctx.quadraticCurveTo(path[i].x, path[i].y, xc, yc);
            i += a;
        }
        ctx.lineTo(path[path.length - 1].x, path[path.length - 1].y);
    }

    drawLine(l) {
        const sx = l.start.x * this.canvas.width, sy = l.start.y * this.canvas.height;
        const ex = l.end.x * this.canvas.width, ey = l.end.y * this.canvas.height;
        this.ctx.beginPath();
        this.ctx.moveTo(sx, sy);
        this.ctx.lineTo(ex, ey);
        this.ctx.strokeStyle = l.color;
        this.ctx.lineWidth = l.thickness;
        this.ctx.stroke();
    }

    drawRectangle(r) {
        const sx = r.start.x * this.canvas.width, sy = r.start.y * this.canvas.height;
        const ex = r.end.x * this.canvas.width, ey = r.end.y * this.canvas.height;
        const w = ex - sx, h = ey - sy;
        this.ctx.beginPath();
        this.ctx.rect(sx, sy, w, h);
        if (r.fill) { this.ctx.fillStyle = r.color; this.ctx.fill(); }
        else { this.ctx.strokeStyle = r.color; this.ctx.lineWidth = r.thickness; this.ctx.stroke(); }
    }

    drawCircle(c) {
        const sx = c.start.x * this.canvas.width, sy = c.start.y * this.canvas.height;
        const ex = c.end.x * this.canvas.width, ey = c.end.y * this.canvas.height;
        const cx = (sx + ex) / 2, cy = (sy + ey) / 2;
        const rx = Math.abs(ex - sx) / 2, ry = Math.abs(ey - sy) / 2;
        this.ctx.beginPath();
        this.ctx.ellipse(cx, cy, rx, ry, 0, 0, 2 * Math.PI);
        if (c.fill) { this.ctx.fillStyle = c.color; this.ctx.fill(); }
        else { this.ctx.strokeStyle = c.color; this.ctx.lineWidth = c.thickness; this.ctx.stroke(); }
    }

    drawEraser(e, shapeObj) {
        const sx = e.start.x * this.canvas.width, sy = e.start.y * this.canvas.height;
        const ex = e.end.x * this.canvas.width, ey = e.end.y * this.canvas.height;
        const w = Math.abs(ex - sx), h = Math.abs(ey - sy);
        const x = Math.min(sx, ex), y = Math.min(sy, ey);

        this.ctx.beginPath();
        this.ctx.rect(x, y, w, h);
        this.ctx.fillStyle = 'rgba(255,255,255)'; 
        this.ctx.fill();

        // 仅当前正在绘制的橡皮擦显示边框
        if (this.currentShape && shapeObj === this.currentShape) {
            this.ctx.save();
            this.ctx.strokeStyle = '#000';
            this.ctx.lineWidth = 1;
            this.ctx.strokeRect(x, y, w, h);
            this.ctx.restore();
        }
    }

    destroy() {
        this.canvas.removeEventListener('mousedown', this.handleMouseDown);
        this.canvas.removeEventListener('mousemove', this.handleMouseMove);
        this.canvas.removeEventListener('mouseup', this.handleMouseUp);
        this.canvas.removeEventListener('mouseleave', this.handleMouseLeave);
        window.removeEventListener('resize', this.resize);
    }
}

export default Canvas;
