<template>
  <view class="recognization-image">
    <!-- 画布绘制阶段 -->
    <view v-if="!resultImage" class="canvas-phase">
      <canvas
        canvas-id="pestCanvas"
        id="pestCanvas"
        :style="{ width: canvasW + 'px', height: canvasH + 'px' }"
      ></canvas>
    </view>

    <!-- 加载中 -->
    <view v-if="loading" class="loading-mask">
      <view class="loading-spinner"></view>
      <text class="loading-text">标注图片生成中...</text>
    </view>

    <!-- 图片查看器：支持拖拽和缩放 -->
    <movable-area
      v-if="resultImage"
      class="image-viewer"
      :style="{ width: containerW + 'px', height: containerH + 'px' }"
    >
      <movable-view
        direction="all"
        :scale="true"
        :scale-min="0.5"
        :scale-max="5"
        :scale-value="currentScale"
        :inertia="true"
        :damping="40"
        :x="initX"
        :y="initY"
        :style="{ width: imgDisplayW + 'px', height: imgDisplayH + 'px' }"
        class="movable-img"
        @scale="onScale"
      >
        <image :src="resultImage" mode="scaleToFill" class="annotated-image" />
      </movable-view>
    </movable-area>

    <!-- 缩放控制按钮 -->
    <!-- <view v-if="resultImage" class="zoom-controls">
      <view class="zoom-btn" @click="zoomIn">
        <text class="zoom-icon">＋</text>
      </view>
      <view class="zoom-btn" @click="zoomOut">
        <text class="zoom-icon">－</text>
      </view>
    </view> -->
  </view>
</template>

<script>
/**
 * 害虫识别图片组件
 * 功能：在原始图片上绘制害虫标注框和标签，生成标注图片，支持拖拽和缩放查看
 *
 * Props:
 *   imageSrc  - 原始图片URL
 *   pestData  - 害虫数据数组 [{startX, startY, width, height, text}]
 *
 * 使用示例:
<RecognizationImage
        :imageSrc="currentImg.addr"
        :pestData="[
          {
            startX: 790.89,
            startY: 211.76,
            width: 169.65,
            height: 189.47,
            text: '二化螟',
          },
          {
            startX: 455.3,
            startY: 313.3,
            width: 102.78,
            height: 90.4,
            text: '二化螟',
          },
          {
            startX: 676.85,
            startY: 472.55,
            width: 135.01,
            height: 101.26,
            text: '草地贪夜蛾',
          },
          {
            startX: 321.37,
            startY: 819.22,
            width: -29.88,
            height: -29.08,
            text: '草地贪夜蛾2号',
          },
          {
            startX: 879.37,
            startY: 79.9,
            width: -49.03,
            height: -45.74,
            text: '666',
          },
          {
            startX: 845.62,
            startY: 643.09,
            width: 14.21,
            height: 15.99,
            text: '6663',
          },
          {
            startX: 370.17,
            startY: 45.58,
            width: 32.24,
            height: 30.45,
            text: '666',
          },
        ]"
        style="width: 100%; height: 500rpx"
      />
 */

// 害虫类型对应的颜色调色板
const COLOR_PALETTE = [
  '#FF0000',
  '#00FFC2',
  '#FF00A8',
  '#120080',
  '#BDFF00',
  '#FFB800',
  '#5E8000',
  '#FF5C00',
  '#00FF75',
  '#00F0FF',
  '#0094FF',
  '#EB00FF',
  '#00C2FF',
  '#C74C4C',
  '#FFFFFF',
  '#FF6B6B',
];

export default {
  name: 'RecognizationImage',
  props: {
    // 原始图片地址
    imageSrc: {
      type: String,
      default: '',
    },
    // 害虫标注数据
    pestData: {
      type: Array,
      default: () => [],
    },
  },
  data() {
    return {
      ctx: null,
      loading: false,
      // 画布尺寸
      canvasW: 300,
      canvasH: 300,
      // 原始图片尺寸
      originalW: 0,
      originalH: 0,
      // 缩放系数
      imageScale: 1, // 图片适配画布的缩放比
      baseScale: 0.25, // 基础缩放参考值
      markScale: 1, // 标注坐标缩放比
      // 生成的标注图片路径
      resultImage: '',
      // 图片显示尺寸（适配容器）
      imgDisplayW: 300,
      imgDisplayH: 300,
      // movable-view 初始位置（居中）
      initX: 0,
      initY: 0,
      // 容器尺寸
      containerW: 300,
      containerH: 300,
      // 害虫类型→颜色映射
      colorMap: {},
      // 当前缩放值
      currentScale: 1,
    };
  },
  watch: {
    imageSrc(newVal) {
      if (newVal) {
        this.render();
      }
    },
    pestData: {
      handler() {
        if (this.imageSrc) {
          this.render();
        }
      },
      deep: true,
    },
  },
  mounted() {
    this.getContainerSize().then(() => {
      if (this.imageSrc) {
        this.render();
      }
    });
  },
  methods: {
    /**
     * 获取容器尺寸
     */
    getContainerSize() {
      return new Promise((resolve) => {
        uni
          .createSelectorQuery()
          .in(this)
          .select('.recognization-image')
          .boundingClientRect((rect) => {
            if (rect && rect.width > 0) {
              this.containerW = rect.width;
              this.containerH = rect.height;
            }
            resolve();
          })
          .exec();
      });
    },

    /**
     * 主渲染流程：加载图片 → 绘制标注 → 导出图片
     */
    async render() {
      if (!this.imageSrc) return;

      this.loading = true;
      this.resultImage = '';
      this.colorMap = {};
      this.currentScale = 1;

      try {
        // 1. 加载图片信息
        const imgInfo = await this.loadImageInfo(this.imageSrc);
        console.log('[RecognizationImage] 图片信息:', imgInfo);

        if (imgInfo.width > 0 && imgInfo.height > 0) {
          this.originalW = imgInfo.width;
          this.originalH = imgInfo.height;
        } else {
          // 回退场景：无法获取尺寸，使用默认比例 4:3
          console.warn(
            '[RecognizationImage] 无法获取图片尺寸，使用默认 4:3 比例',
          );
          this.originalW = 4000;
          this.originalH = 3000;
        }

        // 2. 计算缩放参数和画布尺寸
        this.calcSizes();

        // 3. 等待 canvas 渲染到 DOM
        await this.$nextTick();
        await this.delay(100);

        // 4. 初始化画布上下文
        this.ctx = uni.createCanvasContext('pestCanvas', this);

        // 5. 绘制背景图片（使用 imageScale 缩放到画布尺寸）
        const drawSrc = imgInfo.path || this.imageSrc;
        const displayWidth = this.originalW * this.imageScale;
        const displayHeight = this.originalH * this.imageScale;
        console.log('[RecognizationImage] 绘制参数:', {
          canvas: this.canvasW + 'x' + this.canvasH,
          imageScale: this.imageScale,
          baseScale: this.baseScale,
          markScale: this.markScale,
          displaySize: displayWidth + 'x' + displayHeight,
        });
        this.ctx.drawImage(drawSrc, 0, 0, displayWidth, displayHeight);

        // 6. 绘制害虫标注（使用 markScale 缩放坐标）
        this.drawAnnotations();

        // 8. 执行绘制并导出
        this.ctx.draw(false, () => {
          setTimeout(() => {
            this.exportCanvas();
          }, 300);
        });
      } catch (err) {
        console.error('[RecognizationImage] 渲染失败:', err);
        this.loading = false;
      }
    },

    /**
     * 计算缩放参数和画布尺寸（与 Draw 组件一致的缩放逻辑）
     */
    calcSizes() {
      const cw = this.containerW || 300;
      const ch = this.containerH || 300;
      const canvasAspect = cw / ch;
      const imageAspect = this.originalW / this.originalH;

      // 画布尺寸 = 容器尺寸
      this.canvasW = cw;
      this.canvasH = ch;

      // 计算图片等比缩放系数（适配画布）
      if (imageAspect > canvasAspect) {
        this.imageScale = cw / this.originalW;
      } else {
        this.imageScale = ch / this.originalH;
      }

      // 根据图片宽度定义基础缩放比例
      if (this.originalW >= 5000) {
        this.baseScale = 0.25;
      } else if (this.originalW >= 4000) {
        this.baseScale = 0.31;
      } else {
        this.baseScale = 0.4;
      }

      // 标注坐标缩放比 = imageScale / baseScale
      this.markScale = 1 - (this.baseScale - this.imageScale) / this.baseScale;

      // 图片在画布上的实际显示尺寸
      this.imgDisplayW = Math.round(this.originalW * this.imageScale);
      this.imgDisplayH = Math.round(this.originalH * this.imageScale);

      // movable-view 初始居中
      this.initX = Math.round((cw - this.imgDisplayW) / 2);
      this.initY = Math.round((ch - this.imgDisplayH) / 2);
    },

    /**
     * 加载图片信息（支持多级回退）
     * 1. uni.getImageInfo（首选，返回尺寸+本地路径）
     * 2. uni.downloadFile → uni.getImageInfo（小程序域名白名单场景）
     * 3. H5 直接使用 Image 对象获取尺寸
     */
    loadImageInfo(src) {
      if (!src) return Promise.reject(new Error('imageSrc 为空'));

      return new Promise((resolve, reject) => {
        // 方式1：uni.getImageInfo
        uni.getImageInfo({
          src,
          success: (res) => resolve(res),
          fail: (err1) => {
            console.warn(
              '[RecognizationImage] getImageInfo 失败，尝试 downloadFile:',
              src,
              err1,
            );
            // 方式2：先下载再获取信息
            uni.downloadFile({
              url: src,
              success: (dlRes) => {
                if (dlRes.statusCode === 200) {
                  uni.getImageInfo({
                    src: dlRes.tempFilePath,
                    success: (res) => resolve(res),
                    fail: (err2) => {
                      console.warn(
                        '[RecognizationImage] 下载后 getImageInfo 也失败，使用下载路径:',
                        err2,
                      );
                      // 无法获取尺寸，需要后续处理
                      resolve({
                        path: dlRes.tempFilePath,
                        width: 0,
                        height: 0,
                      });
                    },
                  });
                } else {
                  reject(new Error('下载失败，状态码: ' + dlRes.statusCode));
                }
              },
              fail: (dlErr) => {
                console.error(
                  '[RecognizationImage] downloadFile 也失败:',
                  dlErr,
                );
                reject(dlErr);
              },
            });
          },
        });
      });
    },

    /**
     * 绘制害虫标注（使用 markScale 缩放坐标，与 Draw 组件一致）
     */
    drawAnnotations() {
      if (!this.pestData || !this.pestData.length) return;

      let colorIndex = 0;

      // 根据画布尺寸计算合适的线宽和字号
      const lineWidth = Math.max(1, Math.round(this.canvasW / 200));
      const fontSize = Math.max(10, Math.round(this.canvasW / 25));
      const labelPadding = Math.max(2, Math.round(fontSize / 4));

      this.pestData.forEach((pest) => {
        const { startX, startY, width, height, text } = pest;

        // 为每种害虫分配颜色
        if (!this.colorMap[text]) {
          this.colorMap[text] =
            COLOR_PALETTE[colorIndex % COLOR_PALETTE.length];
          colorIndex++;
        }
        const color = this.colorMap[text];

        // 使用 markScale 缩放坐标到画布空间
        let x = Number(startX) * this.markScale;
        let y = Number(startY) * this.markScale;
        let w = Number(width) * this.markScale;
        let h = Number(height) * this.markScale;

        // 处理反向绘制（宽或高为负数）：调整起点，宽高取绝对值
        if (w < 0) {
          x = x + w;
          w = -w;
        }
        if (h < 0) {
          y = y + h;
          h = -h;
        }
        w = Math.max(1, w);
        h = Math.max(1, h);

        // --- 绘制半透明填充底色 ---
        const r = parseInt(color.slice(1, 3), 16);
        const g = parseInt(color.slice(3, 5), 16);
        const b = parseInt(color.slice(5, 7), 16);
        // this.ctx.setFillStyle(`rgba(${r},${g},${b},0.15)`);
        // this.ctx.fillRect(x, y, w, h);

        // --- 绘制矩形边框 ---
        this.ctx.setStrokeStyle(color);
        this.ctx.setLineWidth(lineWidth);
        this.ctx.strokeRect(x, y, w, h);

        // --- 绘制标签 ---
        if (text) {
          // 标签定位：优先在矩形上方，空间不够则放在矩形内部顶部
          let labelX = x;
          let labelY = y - fontSize - labelPadding;
          if (labelY < 0) {
            labelY = y + labelPadding;
          }

          // 标签文字
          this.ctx.setFillStyle(color);
          this.ctx.setFontSize(fontSize);
          this.ctx.fillText(
            text,
            labelX + labelPadding,
            labelY + fontSize + labelPadding * 0.5,
          );
        }
      });
    },

    /**
     * 手指缩放回调，同步记录当前缩放值
     */
    onScale(e) {
      if (e.detail.scale) {
        this.currentScale = e.detail.scale;
      }
    },

    /**
     * 按钮放大
     */
    zoomIn() {
      this.currentScale = Math.min(5, this.currentScale + 0.3);
    },

    /**
     * 按钮缩小
     */
    zoomOut() {
      this.currentScale = Math.max(0.5, this.currentScale - 0.3);
    },

    /**
     * 导出画布为图片
     */
    exportCanvas() {
      uni.canvasToTempFilePath(
        {
          canvasId: 'pestCanvas',
          quality: 1,
          success: (res) => {
            this.resultImage = res.tempFilePath;
            this.loading = false;
            this.$emit('generated', res.tempFilePath);
          },
          fail: (err) => {
            console.error('[RecognizationImage] 导出失败:', err);
            this.loading = false;
            this.$emit('error', err);
          },
        },
        this,
      );
    },

    /**
     * 工具方法：延迟
     */
    delay(ms) {
      return new Promise((resolve) => setTimeout(resolve, ms));
    },

    /**
     * 对外方法：重新渲染
     */
    refresh() {
      this.render();
    },

    /**
     * 对外方法：获取标注图片路径
     */
    getResultImage() {
      return this.resultImage;
    },
  },
};
</script>

<style scoped>
.recognization-image {
  width: 100%;
  height: 100%;
  position: relative;
  overflow: hidden;
  background-color: #f0f0f0;
}

/* 画布阶段 */
.canvas-phase {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  overflow: hidden;
}

/* 加载遮罩 */
.loading-mask {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background-color: rgba(255, 255, 255, 0.85);
  z-index: 10;
}

.loading-spinner {
  width: 36rpx;
  height: 36rpx;
  border: 4rpx solid #e0e0e0;
  border-top-color: #1890ff;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.loading-text {
  margin-top: 16rpx;
  font-size: 28rpx;
  color: #666666;
}

/* 图片查看器 */
.image-viewer {
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.movable-img {
  display: flex;
  justify-content: center;
  align-items: center;
}

.annotated-image {
  width: 100%;
  height: 100%;
}

/* 缩放控制按钮 */
.zoom-controls {
  position: absolute;
  right: 20rpx;
  bottom: 40rpx;
  display: flex;
  flex-direction: column;
  gap: 16rpx;
  z-index: 20;
}

.zoom-btn {
  width: 64rpx;
  height: 64rpx;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: rgba(0, 0, 0, 0.5);
  border-radius: 50%;
}

.zoom-icon {
  font-size: 36rpx;
  color: #ffffff;
  line-height: 1;
}
</style>
