<template>
  <div class="app-container">
    <div ref="topContainerRef">
      <el-form :model="queryParams" :inline="true" v-show="showSearch" label-width="68px">
        <el-form-item label="地图名称" prop="mapName">
          <el-input v-model="queryParams.mapName" placeholder="请输入地图名称" clearable @keyup.enter="handleQuery" />
        </el-form-item>
        <el-form-item label="地图描述" prop="mapDesc">
          <el-input v-model="queryParams.mapDesc" placeholder="请输入地图描述" clearable @keyup.enter="handleQuery" />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
          <el-button icon="Refresh" @click="resetQuery">重置</el-button>
        </el-form-item>
      </el-form>

      <el-row :gutter="10" class="mb8">
        <el-col :span="1.5">
          <el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
        </el-col>
        <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
      </el-row>
    </div>

    <div :style="containerHeight">
      <el-table v-loading="loading" height="100%" style="width: 100%" :data="tableDataList">
        <el-table-column label="地图名称" align="center" prop="mapName" />
        <el-table-column label="地图描述" align="center" prop="mapDesc" min-width="160" show-overflow-tooltip />
        <el-table-column label="创建人" align="center" prop="createBy" />
        <el-table-column label="创建时间" align="center" prop="createTime" />
        <el-table-column label="操作" class-name="small-padding fixed-width" width="200" fixed="right">
          <template #default="scope">
            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button>
            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>

      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
        v-model:limit="queryParams.pageSize" @pagination="getList" />
    </div>

    <!-- 添加或修改语料库对话框 -->
    <el-dialog :title="title" v-model="open" width="580px" append-to-body>
      <el-form ref="mapRef" :model="form" :rules="rules" label-width="120px">
        <el-form-item label="地图名称" prop="mapName">
          <el-input v-model="form.mapName" placeholder="请输入地图名称" />
        </el-form-item>
        <el-form-item label="地图描述" prop="mapDesc">
          <el-input v-model="form.mapDesc" type="textarea" placeholder="请输入地图描述" />
        </el-form-item>
        <el-form-item label="选择机器人地图">
          <el-col :span="11">
            <el-form-item prop="mapSourceRobotId">
              <el-select v-model="form.mapSourceRobotId" placeholder="请选择机器人" clearable style="width: 100%"
                @change="robotChange">
                <el-option v-for="robot in robotList" :key="robot.value" :label="robot.label" :value="robot.value" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col class="text-center" :span="2">
            <span class="text-gray-500">-</span>
          </el-col>
          <el-col :span="11">
            <el-form-item prop="mapSourceName">
              <el-select v-model="form.mapSourceName" placeholder="请选择地图" clearable style="width: 100%"
                @change="mapChange">
                <el-option v-for="map in mapList" :key="map.value" :label="map.label" :value="map.value" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-form-item>
        <div class="map-container">
          <canvas id="mapCanvas"></canvas>
        </div>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">确 定</el-button>
          <el-button @click="cancel">取 消</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup name="Map">

import { useContainerHeight } from "@/hooks/tableHeight";
import { addMap, updateMap, deleteMap, getMapList } from "../../../api/inspection/map";
import { getRobotList, getMapByRobot, getMapJson } from "../../../api/inspection/robot";
import { onMounted } from "vue";

import {
  worldToScreen,
  screenToWorld,
  drawGrid,
  drawGridlines,
  drawAdvancedAreaList,
  drawAdvancedLineList,
  drawNormalLines,
  drawAdvancedCurveList,
  drawAdvancedPointList,
  drawMapBoundary,
  buildOccupancyGridImage,
  MobileRobot
} from '../cockpit/canvasUtils';
import { de } from "element-plus/es/locale/index.mjs";
import { ElMessage, ElMessageBox } from "element-plus";

const topContainerRef = ref();
const containerHeight = useContainerHeight(topContainerRef);

const mapRef = ref();
const isNew = ref(true);

const tableDataList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);

const total = ref(0);
const title = ref("");

const data = reactive({
  form: {
    mapName: "",
    mapDesc: "",
    mapSourceRobotId: "",
    mapSourceName: "",
  },
  queryParams: {
    pageNum: 1,
    pageSize: 10,
    mapDesc: null,
    mapName: null,
  },
  rules: {
    mapName: [
      { required: true, message: "请输入地图名称", trigger: "change" },
    ],
    mapDesc: [
      { required: true, message: "请输入地图描述", trigger: "blur" },
    ]
  },
});

const { queryParams, form, rules } = toRefs(data);

/** 查询列表 */
function getList() {
  loading.value = true;
  getMapList(queryParams.value).then((response) => {
    tableDataList.value = response.rows;
    total.value = response.total;
    loading.value = false;
  }).catch(() => {
    loading.value = false;
  }).finally(() => {
    loading.value = false;
  });
}

// 取消按钮
function cancel() {
  open.value = false;
  reset();
  if (animationId) {
    cancelAnimationFrame(animationId);
    animationId = null;
  }

  window.removeEventListener('resize', resizeCanvasToContainer)
  canvasCtx.clearRect(0, 0, applicationState.canvasWidthPx, applicationState.canvasHeightPx); 
  canvasCtx = null
}

// 表单重置
function reset() {
  mapRef.value.resetFields();
  form.value = {
    mapName: "",
    mapDesc: "",
    mapSourceRobotId: "",
    mapSourceName: "",
  }
}

/** 搜索按钮操作 */
function handleQuery() {
  queryParams.value.pageNum = 1;
  getList();
}

/** 重置按钮操作 */
function resetQuery() {
  queryParams.value.mapName = null;
  queryParams.value.mapDesc = null;
  handleQuery();
}


/** 新增按钮操作 */
function handleAdd() {
  open.value = true;
  isNew.value = true;
  title.value = "添加地图";
  setTimeout(() => {
    init();
  }, 300);
}

/** 修改按钮操作 */
function handleUpdate(row) {
  form.value = { ...row };
  isNew.value = false;
  open.value = true;
  title.value = "修改地图";
  getMapArr(row.mapSourceRobotId)
  setTimeout(() => {
    init();
    if (form.value.mapSourceName) {
      mapChange()
    }
  }, 300);
}

/** 提交按钮 */
function submitForm() {
  mapRef.value.validate((valid) => {
    if (valid) {
      if (isNew.value) {
        // 调用新增接口
        addMap(form.value).then(() => {
          ElMessage.success("地图添加成功！");
          getList();
          reset();
          open.value = false;
        });
      } else {
        // 调用修改接口
        updateMap(form.value).then(() => {
          ElMessage.success("地图修改成功！");
          getList();
          reset();
          open.value = false;
        });
      }
    }
  });
}

/** 删除按钮操作 */
function handleDelete(row) {
  ElMessageBox.confirm('确定要删除该地图吗？', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning',
  }).then(() => {
    deleteMap(row.id).then(() => {
      ElMessage.success("地图删除成功！");
      getList();
    });
  }).catch(() => {
    // 用户取消删除
  });

}

function parseSmapJson(rawJson) {
  // ── 解析 header ──
  const header = rawJson.header || rawJson;                    // 兼容 header 嵌套或平铺
  const minimumPos = header.minPos || { x: 0, y: 0 };         // 地图左下角（世界坐标）
  const maximumPos = header.maxPos || { x: 1, y: 1 };         // 地图右上角（世界坐标）
  const resolution = header.resolution || 0.05;                // 每像素代表的世界长度（米）

  // ── 计算栅格尺寸 ──
  const worldWidth = maximumPos.x - minimumPos.x;            // 地图世界宽度（米）
  const worldHeight = maximumPos.y - minimumPos.y;            // 地图世界高度（米）
  const gridWidthPx = Math.ceil(worldWidth / resolution) + 1; // 栅格像素宽度
  const gridHeightPx = Math.ceil(worldHeight / resolution) + 1;// 栅格像素高度

  // ── 构建统一数据结构 ──
  const parsedMap = {
    name: header.mapName || 'Untitled',             // 地图名称
    version: header.version || '',                      // 版本号
    mapType: header.mapType || '',                      // 地图类型（如 "2D-Map"）
    resolution: resolution,                                // 分辨率（米/像素）
    originX: minimumPos.x,                              // 地图左下角 X
    originY: minimumPos.y,                              // 地图左下角 Y
    maxX: maximumPos.x,                              // 地图右上角 X
    maxY: maximumPos.y,                              // 地图右上角 Y
    gridWidth: gridWidthPx,                               // 栅格宽度（像素）
    gridHeight: gridHeightPx,                              // 栅格高度（像素）
    // normalPosList: 自由空间点，直接拷贝
    normalPositions: rawJson.normalPosList || [],
    // normalLineList: 直接拷贝，每项含 {startPos:{x,y}, endPos:{x,y}}
    normalLines: rawJson.normalLineList || [],
    // advancedPointList: 直接拷贝，每项含 {className, instanceName, pos:{x,y}, dir, desc, property:[]}
    advancedPoints: rawJson.advancedPointList || [],
    // advancedLineList: 直接拷贝，每项含 {className, instanceName, line:{startPos, endPos}}
    advancedLines: rawJson.advancedLineList || [],
    // advancedCurveList: 直接拷贝，每项含 {className, instanceName, controlPos1, controlPos2, startPos, endPos}
    advancedCurves: rawJson.advancedCurveList || [],
    // advancedAreaList: 直接拷贝，每项含 {className, instanceName, dir, posGroup:[], attribute:{}}
    advancedAreas: rawJson.advancedAreaList || [],
  };

  return parsedMap;
}

const applicationState = {
  parsedMap: null,                                      // 解析后的完整地图数据
  gridOffscreen: null,                                      // 栅格图像（离屏Canvas）
  hoveredElement: null,                                     // 当前悬停的元素 {kind, index}
  animationTimeSeconds: 0,                                  // 全局动画时间戳（秒），用于脉冲动画效果
  camera: {                                                 // 相机参数
    centerX: 0,                                                // 相机中心的世界坐标 X
    centerY: 0,                                                // 相机中心的世界坐标 Y
    pixelsPerMeter: 20,                                        // 缩放：每米对应的屏幕像素数
  },
  canvasWidthPx: 0,                                         // Canvas CSS 逻辑宽度（像素）
  canvasHeightPx: 0,                                        // Canvas CSS 逻辑高度（像素）
  devicePixelRatio: 1,                                      // 设备像素比（高DPI屏幕 > 1）
  mouseState: {                                                 // 鼠标交互状态
    screenX: 0,                                                // 鼠标在 Canvas 上的像素 X
    screenY: 0,                                                // 鼠标在 Canvas 上的像素 Y
    worldX: 0,                                                // 鼠标对应的世界坐标 X
    worldY: 0,                                                // 鼠标对应的世界坐标 Y
    isDragging: false,                                         // 是否正在拖拽平移
  },
  isMapLoaded: false,                                           // 地图加载完成标志,
  layerVisibility: {                                            // 各图层是否可见
    grid: true,                                       // 占据栅格底图
    edges: true,                                       // 墙壁边缘发光
    gridlines: true,                                       // 1米网格辅助线
    normalLines: true,                                       // normalLineList
    advLines: true,                                       // advancedLineList
    curves: true,                                       // advancedCurveList
    points: true,                                       // advancedPointList
    areas: true,                                       // advancedAreaList
  }
};

let mapCanvas;     // 主渲染画布 DOM 元素
let canvasCtx;                 // 2D 渲染上下文

const init = () => {
  mapCanvas = document.getElementById('mapCanvas');
  canvasCtx = mapCanvas.getContext('2d');
}

/**
 * 根据容器尺寸和设备像素比调整 Canvas 大小
 * 在窗口 resize 时自动调用
 */
function resizeCanvasToContainer() {
  const containerRect = mapCanvas.parentElement.getBoundingClientRect(); // 获取容器实际尺寸
  devicePixelRatio = window.devicePixelRatio || 1;             // 获取设备像素比
  applicationState.canvasWidthPx = containerRect.width;                        // 更新逻辑宽度
  applicationState.canvasHeightPx = containerRect.height;                  // 逻辑高度 = 容器高度 - 状态栏高度
  mapCanvas.width = applicationState.canvasWidthPx * devicePixelRatio;         // Canvas 物理像素宽
  mapCanvas.height = applicationState.canvasHeightPx * devicePixelRatio;        // Canvas 物理像素高
  mapCanvas.style.width = applicationState.canvasWidthPx + 'px';               // CSS 显示宽度
  mapCanvas.style.height = applicationState.canvasHeightPx + 'px';              // CSS 显示高度
}

async function loadMapIntoApplication(parsedMap) {
  await new Promise(resolve => setTimeout(resolve, 30));       // 短暂等待让 UI 有机会刷新

  // 保存地图数据到全局状态
  applicationState.parsedMap = parsedMap;
  // 构建栅格图像（带边缘高亮）
  applicationState.gridOffscreen = buildOccupancyGridImage(parsedMap, applicationState.layerVisibility.edges);

  // ── 设置相机初始位置（地图中心）──
  applicationState.camera.centerX = (parsedMap.originX + parsedMap.maxX) / 2; // 水平居中
  applicationState.camera.centerY = (parsedMap.originY + parsedMap.maxY) / 2; // 垂直居中
  // 计算合适的缩放级别，使地图完整显示在画布内
  const worldWidthMeters = parsedMap.maxX - parsedMap.originX; // 地图世界宽度
  const worldHeightMeters = parsedMap.maxY - parsedMap.originY; // 地图世界高度
  const fitScaleX = applicationState.canvasWidthPx / worldWidthMeters;           // 水平方向恰好填满的缩放
  const fitScaleY = applicationState.canvasHeightPx / worldHeightMeters;         // 垂直方向恰好填满的缩放
  applicationState.camera.pixelsPerMeter = Math.max(1, Math.max(fitScaleX, fitScaleY)); // 取较小值并留12%边距

  // 标记加载完成并更新UI
  applicationState.isMapLoaded = true;
}

const bindEvent = () => {
  // ── 鼠标移动：更新坐标、拖拽平移、悬停检测 ──
  mapCanvas.addEventListener('mousemove', (mouseEvent) => {
    const canvasRect = mapCanvas.getBoundingClientRect();        // Canvas 在页面中的位置
    applicationState.mouseState.screenX = mouseEvent.clientX - canvasRect.left; // 鼠标在 Canvas 上的 X
    applicationState.mouseState.screenY = mouseEvent.clientY - canvasRect.top;  // 鼠标在 Canvas 上的 Y
    // 反算世界坐标
    const worldPos = screenToWorld(applicationState.mouseState.screenX, applicationState.mouseState.screenY, applicationState);
    applicationState.mouseState.worldX = worldPos.x;
    applicationState.mouseState.worldY = worldPos.y;

    // 如果正在拖拽，平移相机
    if (applicationState.mouseState.isDragging) {
      applicationState.camera.centerX -= mouseEvent.movementX / applicationState.camera.pixelsPerMeter; // 水平平移
      applicationState.camera.centerY += mouseEvent.movementY / applicationState.camera.pixelsPerMeter; // 垂直平移（Y翻转）
    }
  });

  // ── 鼠标按下：开始拖拽 ──
  mapCanvas.addEventListener('mousedown', () => {
    applicationState.mouseState.isDragging = true;               // 标记拖拽开始
  });

  // ── 鼠标抬起：结束拖拽 ──
  mapCanvas.addEventListener('mouseup', () => {
    applicationState.mouseState.isDragging = false;              // 标记拖拽结束
  });

  // ── 鼠标离开画布：结束拖拽并隐藏 Tooltip ──
  mapCanvas.addEventListener('mouseleave', () => {
    applicationState.mouseState.isDragging = false;
  });

  // ── 滚轮：缩放（向鼠标位置缩放）──
  mapCanvas.addEventListener('wheel', (wheelEvent) => {
    wheelEvent.preventDefault();                                  // 阻止页面滚动
    const zoomFactor = wheelEvent.deltaY > 0 ? 0.88 : 1.12;     // 向下滚动=缩小，向上滚动=放大
    const mouseWorldBefore = screenToWorld(applicationState.mouseState.screenX, applicationState.mouseState.screenY, applicationState); // 缩放前鼠标世界坐标
    applicationState.camera.pixelsPerMeter = Math.max(0.5, Math.min(2000, applicationState.camera.pixelsPerMeter * zoomFactor)); // 应用缩放并钳制范围
    const mouseWorldAfter = screenToWorld(applicationState.mouseState.screenX, applicationState.mouseState.screenY, applicationState);   // 缩放后鼠标世界坐标
    // 调整相机中心，使鼠标指向的世界坐标保持不变
    applicationState.camera.centerX += mouseWorldBefore.x - mouseWorldAfter.x;
    applicationState.camera.centerY += mouseWorldBefore.y - mouseWorldAfter.y;
  }, { passive: false });                                          // passive:false 允许 preventDefault
}

/**
 * 加载 smap JSON 文件
 */
const loadUserFile = async () => {
  try {
    const res = await getMapJson({
      robotId: form.value.mapSourceRobotId,
      mapName: form.value.mapSourceName
    });
    if (res.code === 200) {
      const rawJsonObject = JSON.parse(res.data);        // 解析 JSON
      const parsedMap = parseSmapJson(rawJsonObject);        // 转换为内部结构
      await loadMapIntoApplication(parsedMap);                     // 加载到应用
    }
    
  } catch (parseError) {
    alert('Parse error: ' + parseError.message);                 // 显示错误信息
  }
}

// 声明一个变量保存 requestAnimationFrame 的 ID
let animationId = null;

function renderFrame(timestamp) {
  // 更新动画时间
  applicationState.animationTimeSeconds = (timestamp || 0) / 1000;

  // 设置 Canvas 变换矩阵（考虑设备像素比）
  canvasCtx.setTransform(applicationState.devicePixelRatio, 0, 0, applicationState.devicePixelRatio, 0, 0);
  canvasCtx.clearRect(0, 0, applicationState.canvasWidthPx, applicationState.canvasHeightPx);    // 清空画布

  // 如果地图未加载，跳过绘制
  if (!applicationState.isMapLoaded) {
    animationId = requestAnimationFrame(renderFrame);                         // 继续请求下一帧
    return;
  }

  const map = applicationState.parsedMap;                       // 当前地图数据
  const layers = applicationState.layerVisibility;              // 图层可见性

  // 图层1: 占据栅格底图
  if (layers.grid && applicationState.gridOffscreen) {
    drawGrid(canvasCtx, map, applicationState);
  }

  // 图层2: 网格辅助线（每1米一条）
  if (layers.gridlines) {
    drawGridlines(canvasCtx, applicationState)
  }

  // 图层3: advancedAreaList（半透明多边形区域）
  if (layers.areas) {
    drawAdvancedAreaList(canvasCtx, map, applicationState)
  }

  // 图层4: normalLineList（基础直线，青色 #00e5ff）
  if (layers.normalLines) {
    drawNormalLines(canvasCtx, map, applicationState);
  }

  // 图层5: advancedLineList（高级线，如 ForbiddenLine）
  if (layers.advLines) {
    drawAdvancedLineList(canvasCtx, map, applicationState);
  }

  // 图层6: advancedCurveList（贝塞尔曲线路径，酸绿色 #76ff03）
  if (layers.curves) {
    drawAdvancedCurveList(canvasCtx, map, applicationState);
  }

  // 图层7: advancedPointList（高级点标记，菱形）
  if (layers.points) {
    drawAdvancedPointList(canvasCtx, map, applicationState);
  }


  // 地图边界虚线框
  drawMapBoundary(canvasCtx, map, applicationState);

  // 请求下一帧渲染
  animationId = requestAnimationFrame(renderFrame);
}

const robotList = ref([])
const mapList = ref([])

const getRobotArr = () => {
  getRobotList({
    pageNum: 1,
    pageSize: 10000,
  }).then((response) => {
    robotList.value = response.rows.map(item => ({
      label: item.robotName,
      value: item.id
    }));
  });
}

const getMapArr = async (robotId) => {
  const res = await getMapByRobot(robotId)
  if (res.code === 200) {
    mapList.value = res.data.map(item => {
      return { label: item, value: item }
    })
  }
}

const robotChange = (value) => {
  form.value.mapSourceRobotId = value; // 更新选中的机器人ID
  form.value.mapSourceName = ""; // 清空地图选择
  if (canvasCtx) {
    canvasCtx.clearRect(0, 0, applicationState.canvasWidthPx, applicationState.canvasHeightPx);    // 清空画布
  }

  getMapArr(value);
}

const mapChange = () => {
  loadUserFile();

  if (animationId) {
    cancelAnimationFrame(animationId);
  }
  animationId = requestAnimationFrame(renderFrame);
  window.addEventListener('resize', resizeCanvasToContainer);    // 监听窗口大小变化
  resizeCanvasToContainer();
  setTimeout(() => {

    bindEvent()
  }, 100)
}

onMounted(() => {
  getList();
  getRobotArr();
});

</script>
<style lang="scss" scoped>
.map-container {
  width: 100%;
  height: 300px;
  border: 1px solid #ccc;
}
</style>