import { useInspectionStore } from "@/store/modules/inspection";

const inspectionStore = useInspectionStore();


/**
 * 6位十六进制颜色字符串转为 CSS rgba 字符串
 * @param {string} hex - 如 "#ff6e40"
 * @param {number} alpha - 透明度 0~1
 * @returns {string} CSS rgba 字符串
 */
function hexToCssRgba(hexString, alpha) {
    const r = parseInt(hexString.slice(1, 3), 16);               // 提取 R 分量
    const g = parseInt(hexString.slice(3, 5), 16);               // 提取 G 分量
    const b = parseInt(hexString.slice(5, 7), 16);               // 提取 B 分量
    return `rgba(${r},${g},${b},${alpha})`;
}

/**
 * 将世界坐标转换为 Canvas 屏幕像素坐标
 * 注意：世界坐标 Y 轴向上，Canvas Y 轴向下，因此需要翻转
 * @param {number} worldX - 世界坐标 X（米）
 * @param {number} worldY - 世界坐标 Y（米）
 * @returns {{x: number, y: number}} Canvas 上的屏幕像素坐标
 */
export const worldToScreen = (worldX, worldY, dataStore) => {
    const store = dataStore || inspectionStore;
    const camera = store.camera
    const screenX = (worldX - camera.centerX) * camera.pixelsPerMeter + store.canvasWidthPx / 2;   // 水平偏移 + 居中
    const screenY = -(worldY - camera.centerY) * camera.pixelsPerMeter + store.canvasHeightPx / 2; // 垂直翻转 + 居中
    return { x: screenX, y: screenY };
};

/**
 * 将 Canvas 屏幕像素坐标反算为世界坐标
 * 与 worldToScreen 互为逆运算
 * @param {number} screenX - Canvas 像素 X
 * @param {number} screenY - Canvas 像素 Y
 * @returns {{x: number, y: number}} 世界坐标（米）
 */
export const screenToWorld = (screenX, screenY, dataStore) => {
    const store = dataStore || inspectionStore;
    const camera = store.camera;
    const worldX = (screenX - store.canvasWidthPx / 2) / camera.pixelsPerMeter + camera.centerX;   // 水平反算
    const worldY = -(screenY - store.canvasHeightPx / 2) / camera.pixelsPerMeter + camera.centerY;  // 垂直反算（带翻转）
    return { x: worldX, y: worldY };
};


/**
 * 0xAARRGGBB 整数颜色解码为 {r, g, b, a} 对象
 * @param {number} argbInt - 32位 ARGB 整数，如 0xCCFF0040
 * @returns {{r:number, g:number, b:number, a:number}|null} RGBA 分量 (0~255)，无效输入返回 null
 */
export const decodeArgbInteger = (argbInt) => {
    if (typeof argbInt !== 'number') return null;               // 非数字类型直接返回
    return {
        a: (argbInt >>> 24) & 0xFF,                               // 高8位：Alpha 透明度
        r: (argbInt >>> 16) & 0xFF,                               // 次高8位：Red
        g: (argbInt >>> 8) & 0xFF,                               // 次低8位：Green
        b: argbInt & 0xFF,                               // 低8位：Blue
    };
}

/**
 * 将 decodeArgbInteger 的结果转为 CSS rgba() 字符串
 * @param {{r,g,b,a}} colorObj - RGBA 分量对象
 * @param {number} [alphaOverride] - 可选，覆盖 alpha 值（0~1）
 * @returns {string|null} CSS rgba 字符串，如 "rgba(255,0,64,0.3)"
 */
export const toCssRgba = (colorObj, alphaOverride) => {
    if (!colorObj) return null;                                  // 空对象返回 null
    const alpha = alphaOverride !== undefined                    // 如果提供了覆盖值
        ? alphaOverride                                            // 使用覆盖值
        : colorObj.a / 255;                                        // 否则将 0~255 映射到 0~1
    return `rgba(${colorObj.r},${colorObj.g},${colorObj.b},${alpha})`;
}

/**
 * 栅格底图绘制函数
 * 将预渲染的离屏 Canvas 图像绘制到主 Canvas 上，并根据当前地图范围进行缩放和平移
 * @param {*} canvasCtx 
 * @param {*} map 
 * @param {*} gridOffscreen 
 */
export const drawGrid = (canvasCtx, map, dataStore) => {
    const store = dataStore || inspectionStore;
    const topLeftScreen = worldToScreen(map.originX, map.maxY, store);         // 图像左上角（世界坐标→屏幕）
    const bottomRightScreen = worldToScreen(map.maxX, map.originY, store);     // 图像右下角（世界坐标→屏幕）
    canvasCtx.imageSmoothingEnabled = false;                   // 关闭抗锯齿（保持像素清晰）
    canvasCtx.drawImage(
        store.gridOffscreen,                                          // 离屏 Canvas 图像源
        topLeftScreen.x, topLeftScreen.y,                        // 目标左上角
        bottomRightScreen.x - topLeftScreen.x,                   // 目标宽度
        bottomRightScreen.y - topLeftScreen.y                    // 目标高度
    );
}

/**
 * 网格辅助线（每1米一条）
 * @param {*} canvasCtx 
 * @param {*} canvasWidthPx 
 * @param {*} canvasHeightPx 
 */
export const drawGridlines = (canvasCtx, dataStore) => {
    // 计算当前可视范围的世界坐标
    const store = dataStore || inspectionStore;
    const viewTopLeft = screenToWorld(0, 0, store);               // 视口左上角世界坐标
    const viewBottomRight = screenToWorld(store.canvasWidthPx, store.canvasHeightPx, store); // 视口右下角世界坐标
    const viewMinX = Math.floor(Math.min(viewTopLeft.x, viewBottomRight.x)); // 可视X最小整数
    const viewMaxX = Math.ceil(Math.max(viewTopLeft.x, viewBottomRight.x));  // 可视X最大整数
    const viewMinY = Math.floor(Math.min(viewTopLeft.y, viewBottomRight.y)); // 可视Y最小整数
    const viewMaxY = Math.ceil(Math.max(viewTopLeft.y, viewBottomRight.y));  // 可视Y最大整数

    // 绘制1米间隔的浅色网格线
    canvasCtx.strokeStyle = 'rgba(30,50,80,0.25)';             // 淡蓝灰色
    canvasCtx.lineWidth = 0.5;                                 // 细线
    canvasCtx.beginPath();
    for (let worldX = viewMinX; worldX <= viewMaxX; worldX++) { // 逐列绘制垂直线
        const screenPos = worldToScreen(worldX, 0, store);
        canvasCtx.moveTo(screenPos.x, 0);                        // 从画布顶部
        canvasCtx.lineTo(screenPos.x, store.canvasHeightPx);            // 到画布底部
    }
    for (let worldY = viewMinY; worldY <= viewMaxY; worldY++) { // 逐行绘制水平线
        const screenPos = worldToScreen(0, worldY, store);
        canvasCtx.moveTo(0, screenPos.y);                         // 从画布左边
        canvasCtx.lineTo(store.canvasWidthPx, screenPos.y);             // 到画布右边
    }
    canvasCtx.stroke();
}

/**
 * 绘制高级区域列表
 * @param {*} canvasCtx 
 * @param {*} map 
 * @param {*} dataStore 
 */
export const drawAdvancedAreaList = (canvasCtx, map, dataStore) => {
    const store = dataStore || inspectionStore;
    for (let areaIndex = 0; areaIndex < map.advancedAreas.length; areaIndex++) {
        const area = map.advancedAreas[areaIndex];                // 当前区域
        const vertices = area.posGroup || [];                     // 多边形顶点数组
        if (vertices.length < 3) continue;                        // 少于3个顶点无法构成多边形，跳过

        // ── 颜色：优先使用 attribute 中的 ARGB 整数，否则用默认品红色 ──
        let fillColorCss = 'rgba(224,64,251,0.12)';            // 默认填充（品红半透明）
        let strokeColorCss = 'rgba(224,64,251,0.5)';             // 默认描边（品红较不透明）
        if (area.attribute) {
            const brushColor = decodeArgbInteger(area.attribute.colorBrush); // 解码填充色
            const penColor = decodeArgbInteger(area.attribute.colorPen);   // 解码描边色
            if (brushColor) {
                // 使用原始 alpha 值的一半作为填充透明度，最小 0.06
                fillColorCss = toCssRgba(brushColor, Math.max(0.06, (brushColor.a / 255) * 0.5));
            }
            if (penColor) {
                strokeColorCss = toCssRgba(penColor, 0.6);           // 描边60%不透明
            }
        }

        // ── 绘制多边形 ──
        canvasCtx.fillStyle = fillColorCss;                     // 设置填充色
        canvasCtx.strokeStyle = strokeColorCss;                   // 设置描边色
        canvasCtx.lineWidth = 1.2;                              // 描边宽度
        canvasCtx.beginPath();
        const firstVertexScreen = worldToScreen(vertices[0].x, vertices[0].y, store); // 第一个顶点的屏幕位置
        canvasCtx.moveTo(firstVertexScreen.x, firstVertexScreen.y); // 移动到起点
        for (let i = 1; i < vertices.length; i++) {              // 依次连接后续顶点
            const vertexScreen = worldToScreen(vertices[i].x, vertices[i].y, store);
            canvasCtx.lineTo(vertexScreen.x, vertexScreen.y);
        }
        canvasCtx.closePath();                                    // 闭合路径
        canvasCtx.fill();                                         // 填充
        canvasCtx.stroke();                                       // 描边

        // ── 在多边形质心处绘制区域名称标签 ──
        let centroidWorldX = 0, centroidWorldY = 0;              // 质心世界坐标
        for (const v of vertices) { centroidWorldX += v.x; centroidWorldY += v.y; } // 累加顶点坐标
        centroidWorldX /= vertices.length;                        // 求平均得到质心 X
        centroidWorldY /= vertices.length;                        // 求平均得到质心 Y
        const centroidScreen = worldToScreen(centroidWorldX, centroidWorldY, store);
        canvasCtx.font = '500 8px "JetBrains Mono"';             // 标签字体
        canvasCtx.fillStyle = strokeColorCss;                     // 与描边同色
        canvasCtx.textAlign = 'center';                           // 居中对齐
        canvasCtx.fillText(area.instanceName || '', centroidScreen.x, centroidScreen.y + 3); // 绘制文字
    }
};

/**
 * 绘制高级线列表
 * @param {*} canvasCtx 
 * @param {*} map 
 */
export const drawAdvancedLineList = (canvasCtx, map, dataStore) => {
    const store = dataStore || inspectionStore;
    for (let advLineIndex = 0; advLineIndex < map.advancedLines.length; advLineIndex++) {
        const advLine = map.advancedLines[advLineIndex];          // 当前高级线
        const lineData = advLine.line;                            // 内部的 line 对象
        if (!lineData || !lineData.startPos || !lineData.endPos) continue; // 缺少端点则跳过

        const startScreen = worldToScreen(lineData.startPos.x, lineData.startPos.y, store);
        const endScreen = worldToScreen(lineData.endPos.x, lineData.endPos.y, store);

        // ── 根据 className 决定颜色和线型 ──
        let lineColorHex = '#ff6e40';                             // 默认橙色
        let lineDashPattern = [];                                 // 默认实线（无虚线）
        const classNameLower = (advLine.className || '').toLowerCase();
        if (classNameLower.includes('forbidden')) {               // 禁行线 → 红色虚线
            lineColorHex = '#ff1744';
            lineDashPattern = [8, 4];                               // 虚线模式：8px实 4px空
        } else if (classNameLower.includes('virtual')) {          // 虚拟线 → 橙色虚线
            lineColorHex = '#ffab40';
            lineDashPattern = [4, 4];
        }

        // 绘制高级线
        canvasCtx.save();
        canvasCtx.shadowColor = lineColorHex;                     // 辉光色与线条同色
        canvasCtx.shadowBlur = 4;                                // 辉光半径
        canvasCtx.strokeStyle = lineColorHex;                     // 线条颜色
        canvasCtx.lineWidth = 2.5;                              // 线宽（比基础线粗）
        canvasCtx.setLineDash(lineDashPattern);                   // 设置虚线模式
        canvasCtx.globalAlpha = 0.8;                              // 80%不透明
        canvasCtx.beginPath();
        canvasCtx.moveTo(startScreen.x, startScreen.y);
        canvasCtx.lineTo(endScreen.x, endScreen.y);
        canvasCtx.stroke();
        canvasCtx.setLineDash([]);                                // 恢复实线
        canvasCtx.restore();

        // 在中点绘制名称标签
        // const midpointScreenX = (startScreen.x + endScreen.x) / 2;
        // const midpointScreenY = (startScreen.y + endScreen.y) / 2;
        // canvasCtx.font = '500 8px "JetBrains Mono"';
        // canvasCtx.fillStyle = hexToCssRgba(lineColorHex, 0.55);   // 55%不透明的文字
        // canvasCtx.textAlign = 'center';
        // canvasCtx.fillText(advLine.instanceName || advLine.className || '', midpointScreenX, midpointScreenY - 6);
    }
};

/**
 * 绘制基础直线列表
 * @param {*} canvasCtx 
 * @param {*} map 
 * @param {*} dataStore 
 */
export const drawNormalLines = (canvasCtx, map, dataStore) => {
    const store = dataStore || inspectionStore;
    for (let lineIndex = 0; lineIndex < map.normalLines.length; lineIndex++) {
        const line = map.normalLines[lineIndex];                  // 当前直线
        const startScreen = worldToScreen(line.startPos.x, line.startPos.y, store); // 起点屏幕位置
        const endScreen = worldToScreen(line.endPos.x, line.endPos.y, store);     // 终点屏幕位置

        // 绘制发光直线
        canvasCtx.save();
        canvasCtx.shadowColor = '#00e5ff';                        // 阴影颜色（产生辉光）
        canvasCtx.shadowBlur = 5;                                // 辉光扩散半径
        canvasCtx.strokeStyle = '#00e5ff';                        // 线条颜色：青色
        canvasCtx.lineWidth = 2;                                // 线宽
        canvasCtx.globalAlpha = 0.8;                              // 80%不透明
        canvasCtx.beginPath();
        canvasCtx.moveTo(startScreen.x, startScreen.y);           // 从起点
        canvasCtx.lineTo(endScreen.x, endScreen.y);               // 到终点
        canvasCtx.stroke();
        canvasCtx.restore();

        // 在中点绘制方向箭头
        const midpointX = (startScreen.x + endScreen.x) / 2;     // 中点X
        const midpointY = (startScreen.y + endScreen.y) / 2;     // 中点Y
        const arrowAngle = Math.atan2(endScreen.y - startScreen.y, endScreen.x - startScreen.x); // 线段方向角
        const arrowLength = 5;                                    // 箭头长度
        canvasCtx.fillStyle = 'rgba(0,229,255,0.6)';              // 箭头填充色
        canvasCtx.beginPath();
        canvasCtx.moveTo(midpointX + Math.cos(arrowAngle) * arrowLength, midpointY + Math.sin(arrowAngle) * arrowLength); // 箭头尖端
        canvasCtx.lineTo(midpointX + Math.cos(arrowAngle + 2.5) * 4, midpointY + Math.sin(arrowAngle + 2.5) * 4);       // 左翼
        canvasCtx.lineTo(midpointX + Math.cos(arrowAngle - 2.5) * 4, midpointY + Math.sin(arrowAngle - 2.5) * 4);       // 右翼
        canvasCtx.closePath();
        canvasCtx.fill();
    }
};

/**
 * 绘制高级曲线列表
 * @param {*} canvasCtx 
 * @param {*} map 
 * @param {*} dataStore 
 */
export const drawAdvancedCurveList = (canvasCtx, map, dataStore) => {
    const store = dataStore || inspectionStore;
    for (let curveIndex = 0; curveIndex < map.advancedCurves.length; curveIndex++) {
        const curve = map.advancedCurves[curveIndex];             // 当前曲线

        // 提取起点和终点的 pos（注意：startPos/endPos 是 {instanceName, pos:{x,y}} 结构）
        const startPoint = curve.startPos?.pos;                   // 起点世界坐标
        const endPoint = curve.endPos?.pos;                     // 终点世界坐标
        const controlPoint1 = curve.controlPos1;                  // 第一控制点（直接 {x,y}）
        const controlPoint2 = curve.controlPos2;                  // 第二控制点（直接 {x,y}）
        if (!startPoint || !endPoint) continue;                   // 缺少端点则跳过

        // 转换为屏幕坐标
        const startScreen = worldToScreen(startPoint.x, startPoint.y, store);
        const endScreen = worldToScreen(endPoint.x, endPoint.y, store);
        const cp1Screen = controlPoint1 ? worldToScreen(controlPoint1.x, controlPoint1.y, store) : null; // 可能不存在
        const cp2Screen = controlPoint2 ? worldToScreen(controlPoint2.x, controlPoint2.y, store) : null;

        // ── 绘制贝塞尔曲线（虚线）──
        canvasCtx.save();
        canvasCtx.shadowColor = '#76ff03';                        // 酸绿色辉光
        canvasCtx.shadowBlur = 5;
        canvasCtx.strokeStyle = '#76ff03';                        // 酸绿色线条
        canvasCtx.lineWidth = 2;
        canvasCtx.setLineDash([8, 5]);                            // 虚线模式
        canvasCtx.globalAlpha = 0.85;
        canvasCtx.beginPath();
        canvasCtx.moveTo(startScreen.x, startScreen.y);           // 起点
        if (cp1Screen && cp2Screen) {
            // 有2个控制点 → 三次贝塞尔 (cubic bezier)
            canvasCtx.bezierCurveTo(cp1Screen.x, cp1Screen.y, cp2Screen.x, cp2Screen.y, endScreen.x, endScreen.y);
        } else if (cp1Screen) {
            // 仅1个控制点 → 二次贝塞尔 (quadratic bezier)
            canvasCtx.quadraticCurveTo(cp1Screen.x, cp1Screen.y, endScreen.x, endScreen.y);
        } else {
            // 无控制点 → 直线
            canvasCtx.lineTo(endScreen.x, endScreen.y);
        }
        canvasCtx.stroke();
        canvasCtx.setLineDash([]);                                // 恢复实线
        canvasCtx.restore();

        // ── 在 t=0.5 处绘制方向箭头 ──
        if (cp1Screen && cp2Screen) {
            const t = 0.5;                                          // 参数 t = 0.5（曲线中点）
            const oneMinusT = 0.5;                                  // 1-t = 0.5
            // 三次贝塞尔公式计算中点坐标
            const arrowX = oneMinusT ** 3 * startScreen.x + 3 * oneMinusT ** 2 * t * cp1Screen.x + 3 * oneMinusT * t ** 2 * cp2Screen.x + t ** 3 * endScreen.x;
            const arrowY = oneMinusT ** 3 * startScreen.y + 3 * oneMinusT ** 2 * t * cp1Screen.y + 3 * oneMinusT * t ** 2 * cp2Screen.y + t ** 3 * endScreen.y;
            // 三次贝塞尔的一阶导数（切线方向）
            const tangentX = 3 * oneMinusT ** 2 * (cp1Screen.x - startScreen.x) + 6 * oneMinusT * t * (cp2Screen.x - cp1Screen.x) + 3 * t ** 2 * (endScreen.x - cp2Screen.x);
            const tangentY = 3 * oneMinusT ** 2 * (cp1Screen.y - startScreen.y) + 6 * oneMinusT * t * (cp2Screen.y - cp1Screen.y) + 3 * t ** 2 * (endScreen.y - cp2Screen.y);
            const tangentAngle = Math.atan2(tangentY, tangentX);     // 切线角度

            // 绘制箭头
            canvasCtx.fillStyle = 'rgba(118,255,3,0.7)';
            canvasCtx.beginPath();
            canvasCtx.moveTo(arrowX + Math.cos(tangentAngle) * 5, arrowY + Math.sin(tangentAngle) * 5);
            canvasCtx.lineTo(arrowX + Math.cos(tangentAngle + 2.5) * 4, arrowY + Math.sin(tangentAngle + 2.5) * 4);
            canvasCtx.lineTo(arrowX + Math.cos(tangentAngle - 2.5) * 4, arrowY + Math.sin(tangentAngle - 2.5) * 4);
            canvasCtx.closePath();
            canvasCtx.fill();

            // 绘制控制点小圆（辅助调试用）
            canvasCtx.fillStyle = 'rgba(118,255,3,0.25)';           // 浅绿色半透明
            for (const controlScreen of [cp1Screen, cp2Screen]) {
                canvasCtx.beginPath();
                canvasCtx.arc(controlScreen.x, controlScreen.y, 2.5, 0, Math.PI * 2); // 半径2.5px的小圆
                canvasCtx.fill();
            }
        }

        // ── 曲线名称标签 ──
        // canvasCtx.font = '500 7px "JetBrains Mono"';
        // canvasCtx.fillStyle = 'rgba(118,255,3,0.5)';
        // canvasCtx.textAlign = 'center';
        // const labelScreenY = Math.min(startScreen.y, endScreen.y) - 8; // 标签放在最高点上方
        // canvasCtx.fillText(curve.instanceName || '', (startScreen.x + endScreen.x) / 2, labelScreenY);
    }
};

/**
 * 绘制高级点列表
 * @param {*} canvasCtx 
 * @param {*} map 
 * @param {*} dataStore 
 */
export const drawAdvancedPointList = (canvasCtx, map, dataStore) => {
    const store = dataStore || inspectionStore;
    for (let pointIndex = 0; pointIndex < map.advancedPoints.length; pointIndex++) {
        const advPoint = map.advancedPoints[pointIndex];          // 当前高级点
        const pointScreen = worldToScreen(advPoint.pos.x, advPoint.pos.y, store); // 屏幕位置

        // 判断是否被鼠标悬停
        const isHovered = store.hoveredElement &&
            store.hoveredElement.kind === 'point' &&
            store.hoveredElement.index === pointIndex;

        // ── 根据 className 决定颜色 ──
        let pointColorHex = '#ffd600';                            // 默认琥珀色
        const classNameLower = (advPoint.className || '').toLowerCase();
        if (classNameLower.includes('landmark') || classNameLower.includes('land')) {
            pointColorHex = '#ffd600';                              // LandMark → 琥珀色
        } else if (classNameLower.includes('charge')) {
            pointColorHex = '#22c55e';                              // 充电点 → 绿色
        } else if (classNameLower.includes('load')) {
            pointColorHex = '#3b82f6';                              // 装载点 → 蓝色
        } else if (classNameLower.includes('work') || classNameLower.includes('process')) {
            pointColorHex = '#a855f7';                              // 工位 → 紫色
        } else if (classNameLower.includes('station')) {
            pointColorHex = '#00e5ff';                              // 站点 → 青色
        }

        // ── 绘制菱形标记 ──
        const diamondRadius = isHovered ? 8 : 5;                 // 悬停时放大
        const pulseAlpha = isHovered ? Math.sin(store.animationTimeSeconds * 5) * 0.2 + 0.8 : 1; // 悬停时脉冲闪烁

        canvasCtx.save();
        canvasCtx.globalAlpha = pulseAlpha;                       // 应用透明度
        canvasCtx.shadowColor = pointColorHex;                    // 辉光颜色
        canvasCtx.shadowBlur = isHovered ? 18 : 8;              // 悬停时增强辉光

        // 绘制旋转45度的正方形（菱形）
        canvasCtx.fillStyle = pointColorHex;
        canvasCtx.beginPath();
        canvasCtx.moveTo(pointScreen.x, pointScreen.y - diamondRadius);          // 上顶点
        canvasCtx.lineTo(pointScreen.x + diamondRadius * 0.7, pointScreen.y);    // 右顶点
        canvasCtx.lineTo(pointScreen.x, pointScreen.y + diamondRadius);          // 下顶点
        canvasCtx.lineTo(pointScreen.x - diamondRadius * 0.7, pointScreen.y);    // 左顶点
        canvasCtx.closePath();
        canvasCtx.fill();

        // 中心白色小圆点（指示精确位置）
        canvasCtx.shadowBlur = 0;
        canvasCtx.fillStyle = '#fff';
        canvasCtx.globalAlpha = 0.9;
        canvasCtx.beginPath();
        canvasCtx.arc(pointScreen.x, pointScreen.y, 1.8, 0, Math.PI * 2); // 半径1.8px
        canvasCtx.fill();
        canvasCtx.restore();

        // ── 方向箭头（基于 dir 字段，弧度）──
        if (advPoint.dir !== undefined && advPoint.dir !== null) {
            // dir 可能是字符串（smap 样例中为 "-1.5759999999999958"）或数字
            const dirRadians = typeof advPoint.dir === 'string' ? parseFloat(advPoint.dir) : advPoint.dir;
            if (!isNaN(dirRadians)) {                               // 有效方向角
                const arrowLengthPx = 12;                            // 箭头长度（屏幕像素）
                canvasCtx.strokeStyle = hexToCssRgba(pointColorHex, 0.5); // 半透明的线条
                canvasCtx.lineWidth = 1;
                canvasCtx.beginPath();
                canvasCtx.moveTo(pointScreen.x, pointScreen.y);       // 从点中心出发
                // 注意：世界坐标 Y 向上，但 atan2 使用的 dir 是标准数学角，屏幕 Y 翻转后取负
                canvasCtx.lineTo(
                    pointScreen.x + Math.cos(dirRadians) * arrowLengthPx,
                    pointScreen.y - Math.sin(dirRadians) * arrowLengthPx // Y 翻转
                );
                canvasCtx.stroke();
            }
        }

        // ── 名称标签 ──
        canvasCtx.font = '500 7px "JetBrains Mono"';
        canvasCtx.fillStyle = hexToCssRgba(pointColorHex, 0.7);
        canvasCtx.textAlign = 'center';
        canvasCtx.fillText(advPoint.instanceName || '', pointScreen.x, pointScreen.y - diamondRadius - 4);
    }
}

/**
 * 绘制地图边界
 * @param {*} canvasCtx 
 * @param {*} map 
 * @param {*} dataStore 
 */
export const drawMapBoundary = (canvasCtx, map, dataStore) => {
    const store = dataStore || inspectionStore;
    const boundaryTopLeft = worldToScreen(map.originX, map.maxY, store);   // 边界左上角屏幕位置
    const boundaryBottomRight = worldToScreen(map.maxX, map.originY, store);   // 边界右下角屏幕位置
    canvasCtx.strokeStyle = 'rgba(0,229,160,0.1)';                      // 极淡的青绿色
    canvasCtx.lineWidth = 1;
    canvasCtx.setLineDash([5, 4]);                                      // 虚线
    canvasCtx.strokeRect(
        boundaryTopLeft.x, boundaryTopLeft.y,
        boundaryBottomRight.x - boundaryTopLeft.x,
        boundaryBottomRight.y - boundaryTopLeft.y
    );
    canvasCtx.setLineDash([]);                                          // 恢复实线
};

/**
 * 从 normalPosList 构建占据栅格图像
 *
 * 原理：normalPosList 中每个点标记一个自由通行格子。
 *       未出现在列表中的格子 = 障碍物（墙壁）
 *       墙壁格子如果紧邻自由格子，则标记为"墙壁边缘"，渲染高亮
 *
 * @param {Object} parsedMap - parseSmapJson 的输出
 * @param {boolean} showEdgeGlow - 是否计算墙壁边缘高亮效果
 * @returns {HTMLCanvasElement} 离屏 Canvas 元素，包含渲染好的栅格图像
 */
export const buildOccupancyGridImage = (parsedMap, showEdgeGlow) => {
    const gridW = parsedMap.gridWidth;                           // 栅格宽度（像素）
    const gridH = parsedMap.gridHeight;                          // 栅格高度（像素）
    const originX = parsedMap.originX;                           // 世界坐标原点 X
    const originY = parsedMap.originY;                           // 世界坐标原点 Y
    const resolution = parsedMap.resolution;                     // 分辨率

    // ── 第一步：遍历 normalPosList，标记自由空间 ──
    const occupancyGrid = new Uint8Array(gridW * gridH);        // 0=墙壁, 1=自由空间
    for (const freeSpacePoint of parsedMap.normalPositions) {
        // 将世界坐标转换为栅格像素坐标
        const gridColX = Math.floor((freeSpacePoint.x - originX) / resolution); // 列号（从左到右）
        const pixelRowFromBottom = Math.floor((freeSpacePoint.y - originY) / resolution); // 行号（从下到上，世界坐标系）
        const imageRowY = gridH - 1 - pixelRowFromBottom;         // 翻转为图像行号（从上到下）
        // 安全边界检查后标记为自由空间
        if (gridColX >= 0 && gridColX < gridW && imageRowY >= 0 && imageRowY < gridH) {
            occupancyGrid[imageRowY * gridW + gridColX] = 1;        // 标记该格为自由
        }
    }

    // ── 第二步：遍历每个格子，按类型着色 ──
    const offscreenCanvas = document.createElement('canvas');    // 创建离屏 Canvas
    offscreenCanvas.width = gridW;                              // 设置尺寸
    offscreenCanvas.height = gridH;
    const offscreenCtx = offscreenCanvas.getContext('2d');        // 获取上下文
    const imageData = offscreenCtx.createImageData(gridW, gridH);// 创建 ImageData
    const pixelData = imageData.data;                            // 像素数据数组 (RGBA 扁平排列)

    // 定义三种颜色
    const FREE_SPACE_R = 10, FREE_SPACE_G = 16, FREE_SPACE_B = 30;    // 自由空间：深蓝黑
    const WALL_INTERIOR_R = 22, WALL_INTERIOR_G = 36, WALL_INTERIOR_B = 64; // 墙壁内部：深蓝
    const WALL_EDGE_R = 45, WALL_EDGE_G = 130, WALL_EDGE_B = 255;     // 墙壁边缘：亮蓝

    for (let rowY = 0; rowY < gridH; rowY++) {                   // 逐行扫描
        for (let colX = 0; colX < gridW; colX++) {                 // 逐列扫描
            const gridIndex = rowY * gridW + colX;                   // 一维数组索引
            const pixelOffset = gridIndex << 2;                      // RGBA 偏移（×4）

            if (occupancyGrid[gridIndex] === 1) {
                // ── 自由空间 ──
                pixelData[pixelOffset] = FREE_SPACE_R;             // R
                pixelData[pixelOffset + 1] = FREE_SPACE_G;             // G
                pixelData[pixelOffset + 2] = FREE_SPACE_B;             // B
                pixelData[pixelOffset + 3] = 255;                      // A（不透明）
            } else {
                // ── 障物（墙壁）── 判断是否为边缘
                let isAdjacentToFreeSpace = false;                     // 是否紧邻自由空间
                if (showEdgeGlow) {                                    // 仅在启用边缘效果时检测
                    if (rowY > 0 && occupancyGrid[(rowY - 1) * gridW + colX] === 1) isAdjacentToFreeSpace = true;    // 上方
                    else if (rowY < gridH - 1 && occupancyGrid[(rowY + 1) * gridW + colX] === 1) isAdjacentToFreeSpace = true; // 下方
                    else if (colX > 0 && occupancyGrid[rowY * gridW + colX - 1] === 1) isAdjacentToFreeSpace = true;   // 左方
                    else if (colX < gridW - 1 && occupancyGrid[rowY * gridW + colX + 1] === 1) isAdjacentToFreeSpace = true;   // 右方
                }
                if (isAdjacentToFreeSpace) {
                    // 墙壁边缘：亮蓝色
                    pixelData[pixelOffset] = WALL_EDGE_R;
                    pixelData[pixelOffset + 1] = WALL_EDGE_G;
                    pixelData[pixelOffset + 2] = WALL_EDGE_B;
                    pixelData[pixelOffset + 3] = 255;
                } else {
                    // 墙壁内部：深蓝色
                    pixelData[pixelOffset] = WALL_INTERIOR_R;
                    pixelData[pixelOffset + 1] = WALL_INTERIOR_G;
                    pixelData[pixelOffset + 2] = WALL_INTERIOR_B;
                    pixelData[pixelOffset + 3] = 255;
                }
            }
        }
    }

    // 将 ImageData 绘制到离屏 Canvas 上
    offscreenCtx.putImageData(imageData, 0, 0);
    return offscreenCanvas;
}

export class MobileRobot {
    constructor(id, name, x, y, angleRad = 0, color= "#00D4FF", imageUrl = null) {
        this.id = id;
        this.name = name;
        this.x = x;          // 世界坐标X (米)
        this.y = y;          // 世界坐标Y (米)
        this.angle = angleRad; // 朝向弧度
        this.imageUrl = imageUrl || '/bot.svg';
        // 预加载图片 (可选)
        this.imgElement = null;
        if (this.imageUrl) {
            this.init(color, this.imageUrl)
        }
    }

    async init(color, imageUrl) {
        const response = await fetch(imageUrl);
            let svgText = await response.text();
            // 替换颜色
            svgText = svgText.replace(/currentColor/g, color);
            svgText = svgText.replace(/stroke="[^"]*"/g, `stroke="${color}"`);
            // 创建Blob URL
            const blob = new Blob([svgText], { type: 'image/svg+xml' });
            const url = URL.createObjectURL(blob);
            this.imgElement = new Image();
            this.imgElement.src = url;
    }
    // 命中检测: 检查世界坐标是否在机器人区域内 (半径0.35米)
    hitTest(worldX, worldY, pixelsPerMeter){
        const dx = worldX - this.x;
        const dy = worldY - this.y;
        const distance = Math.hypot(dx, dy);
        const hitRadius = 0.35; // 米
        return distance < hitRadius;
    }

    // 绘制到canvas上下文 (屏幕坐标)
    draw(ctx, screenX, screenY, scale = 1) {
        const size = 18; // 绘制大小px
        if (this.imgElement && this.imgElement.complete) {
            ctx.save();
            ctx.translate(screenX, screenY);
            ctx.rotate(-this.angle); // canvas Y向下, 角度翻转适配
            ctx.drawImage(this.imgElement, -size / 2, -size / 2, size, size);
            ctx.restore();
        }
        // 名字标签
        ctx.font = '12px "JetBrains Mono"';
        ctx.fillStyle = '#a0c0f0';
        ctx.shadowBlur = 0;
        ctx.fillText(this.name, screenX - 30, screenY - 20);
    }

    // 更新位置
    setPosition(x, y) { this.x = x; this.y = y; }
    setAngle(rad) { this.angle = rad; }
}

