<script setup lang="ts">
import { computed, onMounted, ref, useTemplateRef, onUnmounted } from 'vue';
import { useRoute } from 'vue-router';
import { showConfirmDialog } from 'vant';

// question 属性
const element = defineModel<question>('element', { default: {} });
// 属性框是否激活
const active = defineModel<boolean>('active', { default: false });
// 题目索引
const index = defineModel<number | string>('index', { default: 0 });
// 答案
const answer = defineModel<string>('answer', { default: '' });
// 错误信息
const errorMessage = defineModel<string>('errorMessage', { default: '' });

const isPreview = defineModel('isPreview', { default: false });
const signatureCanvas = useTemplateRef('signatureCanvas');

const canvasWidth = ref(window.innerWidth * 0.8);
const canvasHeight = computed(() => canvasWidth.value / 1);
const isEraser = ref(false);

let ctx: CanvasRenderingContext2D;
let isDrawing = false;
const undoStack = ref<ImageData[]>([]);
const currentStep = ref(-1);

// 保存当前状态
const saveState = () => {
  if (!ctx || !signatureCanvas.value) return;
  const imageData = ctx.getImageData(
    0,
    0,
    signatureCanvas.value.width,
    signatureCanvas.value.height
  );
  currentStep.value += 1;
  // 移除当前步骤之后的所有状态（处理在撤销后又进行了新的绘制的情况）
  undoStack.value.splice(currentStep.value);
  undoStack.value.push(imageData);
};

// 设置画笔样式
const setPenStyle = () => {
  if (!ctx) return;
  if (isEraser.value) {
    ctx.globalCompositeOperation = 'destination-out';
    ctx.lineWidth = 20;
  } else {
    ctx.globalCompositeOperation = 'source-over';
    ctx.lineWidth = 2;
  }
  ctx.strokeStyle = '#000';
  ctx.lineCap = 'round';
  ctx.lineJoin = 'round';
};

// 切换画笔/橡皮擦
const togglePen = () => {
  isEraser.value = !isEraser.value;
  setPenStyle();
};

const route = useRoute();

onMounted(() => {
  // 设置页面刷新标记
  sessionStorage.setItem('is_page_refresh', '1');

  if (!signatureCanvas.value) return;

  // 获取 canvas 上下文
  ctx = signatureCanvas.value.getContext('2d')!;
  if (!ctx) return;
  setPenStyle();

  // 保存初始空白状态
  saveState();

  // 触摸开始，开始绘制适用于移动设备
  signatureCanvas.value?.addEventListener('touchstart', (e) => {
    // if (!active.value) {
    //   return;
    // }
    // 防止页面滚动
    e.preventDefault();
    isDrawing = true;
    const rect = signatureCanvas.value!.getBoundingClientRect();
    const touch = e.touches[0];
    ctx.beginPath();
    ctx.moveTo(touch.clientX - rect.left, touch.clientY - rect.top);
  });

  signatureCanvas.value?.addEventListener('touchmove', (e) => {
    e.preventDefault();
    if (!isDrawing) return;
    const rect = signatureCanvas.value!.getBoundingClientRect();
    const touch = e.touches[0];
    ctx.lineTo(touch.clientX - rect.left, touch.clientY - rect.top);
    ctx.stroke();
  });

  signatureCanvas.value?.addEventListener('touchend', () => {
    if (isDrawing) {
      saveState();
    }
    isDrawing = false;
  });

  signatureCanvas.value?.addEventListener('touchcancel', () => {
    isDrawing = false;
  });

  // 鼠标事件处理
  signatureCanvas.value?.addEventListener('mousedown', (e) => {
    isDrawing = true;
    const rect = signatureCanvas.value!.getBoundingClientRect();
    ctx.beginPath();
    ctx.moveTo(e.clientX - rect.left, e.clientY - rect.top);
  });

  signatureCanvas.value?.addEventListener('mousemove', (e) => {
    if (!isDrawing) return;
    const rect = signatureCanvas.value!.getBoundingClientRect();
    ctx.lineTo(e.clientX - rect.left, e.clientY - rect.top);
    ctx.stroke();
  });

  signatureCanvas.value?.addEventListener('mouseup', () => {
    if (isDrawing) {
      saveState();
    }
    isDrawing = false;
  });

  signatureCanvas.value?.addEventListener('mouseleave', () => {
    if (isDrawing) {
      saveState();
    }
    isDrawing = false;
  });
});

/**
 * 清除画布
 */
const clearCanvas = () => {
  if (!ctx || !signatureCanvas.value) return;
  ctx.clearRect(0, 0, signatureCanvas.value.width, signatureCanvas.value.height);
  saveState();
};

/**
 * 保存画布
 * @param type {'dataUrl' | 'blob'} 保存类型
 * @return {string | Blob | undefined | null}
 */
const saveCanvas = (type: 'dataUrl' | 'blob'): string | Blob | undefined | null => {
  let img: string | Blob | undefined | null = undefined;
  if (!ctx || !signatureCanvas.value) return;
  if (type === 'blob') {
    signatureCanvas.value.toBlob(
      (blob) => {
        img = blob;
      },
      'image/png',
      { quality: 0.9 }
    );
    return img;
  }

  if (type === 'dataUrl') return signatureCanvas.value.toDataURL('image/png');
};

/**
 * 撤销
 */
const undo = () => {
  if (!ctx || !signatureCanvas.value || currentStep.value <= 0) return;
  currentStep.value -= 1;
  const imageData = undoStack.value[currentStep.value];
  if (imageData) {
    ctx.putImageData(imageData, 0, 0);
  }
};

const emit = defineEmits(['update:element']);
const emitValue = () => {
  emit('update:element', element.value);
};

let aIndex = 1;
/**
 * 上传文件
 */
async function handleUploadImg() {
  // const file = new File([saveCanvas('blob')!], 'sign.png', { type: 'image/png' });
  // const res = await CommonApi.cosUpload(file);
  // console.log(`sign upload url`, res);
  // // 传递答案
  // answer.value = res;
  showConfirmDialog({
    title: '提示',
    message: '上传成功',
    showCancelButton: false
  }).then(() => {
    aIndex++;
    answer.value = 'this is test' + aIndex;
  });

  saveCanvasState();
}

/**
 * 保存canvas 状态
 * 当组件注销时需要保存状态，存到本地indexDB ，然后等待下次组件加载时恢复
 * 但在页面刷新时不保存
 */
function saveCanvasState() {
  if (!ctx || !signatureCanvas.value) return;
  const imageData = ctx.getImageData(0, 0, canvasWidth.value, canvasHeight.value);
  undoStack.value.push(imageData);
  currentStep.value = undoStack.value.length - 1;

  // 检查是否是页面刷新或关闭
  const isPageRefresh = !sessionStorage.getItem('is_page_refresh');

  // 如果是页面刷新，则不保存状态
  if (isPageRefresh) {
    // 清除之前保存的状态
    if (window.indexedDB) {
      try {
        const request = window.indexedDB.open('canvasState', 1);
        request.onsuccess = (e: Event) => {
          const db = (e.target as IDBOpenDBRequest).result;
          const tx = db.transaction('canvasState', 'readwrite');
          const store = tx.objectStore('canvasState');
          store.delete(element.value.id || 'default_id');
          tx.oncomplete = () => {
            db.close();
          };
        };
      } catch (err) {
        console.error('Error clearing canvas state:', err);
      }
    }
    return;
  }

  // 没有 indexDB, 不保存
  if (!window.indexedDB) return;

  // 将 canvas 转换为 base64 字符串
  const canvasDataUrl = signatureCanvas.value.toDataURL('image/png');

  // 保存到 indexDB
  const request = window.indexedDB.open('canvasState', 1);

  // 当数据库首次创建或版本升级时创建对象存储
  request.onupgradeneeded = (e: IDBVersionChangeEvent) => {
    const db = (e.target as IDBOpenDBRequest).result;
    if (!db.objectStoreNames.contains('canvasState')) {
      db.createObjectStore('canvasState');
    }
  };

  request.onerror = (e: Event) => {
    console.error('Failed to open indexDB', e);
  };

  request.onsuccess = (e: Event) => {
    const db = (e.target as IDBOpenDBRequest).result;
    try {
      const tx = db.transaction('canvasState', 'readwrite');
      const store = tx.objectStore('canvasState');
      // 只存储 base64 字符串，而不是 ImageData 对象
      store.put(
        { canvasDataUrl, currentStep: currentStep.value },
        element.value.id || 'default_id'
      );
      tx.oncomplete = () => {
        db.close();
      };
    } catch (err) {
      console.error('Error saving canvas state:', err);
    }
  };
}
onUnmounted(() => {
  // 当组件注销时，保存状态
  saveCanvasState();
});

/**
 * 恢复canvas 状态
 * 当组件加载时需要从localStorage恢复状态
 */
function restoreCanvasState() {
  // 没有 indexDB, 不恢复
  if (!window.indexedDB) return;
  if (!ctx || !signatureCanvas.value) return;

  const request = window.indexedDB.open('canvasState', 1);

  // 当数据库首次创建或版本升级时创建对象存储
  request.onupgradeneeded = (e: IDBVersionChangeEvent) => {
    const db = (e.target as IDBOpenDBRequest).result;
    if (!db.objectStoreNames.contains('canvasState')) {
      db.createObjectStore('canvasState');
    }
  };

  request.onerror = (e: Event) => {
    console.error('Failed to open indexDB', e);
  };

  request.onsuccess = (e: Event) => {
    const db = (e.target as IDBOpenDBRequest).result;
    try {
      const tx = db.transaction('canvasState', 'readonly');
      const store = tx.objectStore('canvasState');
      const getRequest = store.get(element.value.id || 'default_id');

      getRequest.onsuccess = (e: Event) => {
        const savedState = (e.target as IDBRequest).result;
        if (savedState && savedState.canvasDataUrl) {
          // 从 base64 字符串恢复 canvas
          const img = new Image();
          img.onload = () => {
            ctx.clearRect(0, 0, canvasWidth.value, canvasHeight.value);
            ctx.drawImage(img, 0, 0);
            // 恢复后获取当前 ImageData 并存入 undoStack
            const imageData = ctx.getImageData(0, 0, canvasWidth.value, canvasHeight.value);
            undoStack.value = [imageData];
            currentStep.value = 0;
          };
          img.src = savedState.canvasDataUrl;
        }
        db.close();
      };

      getRequest.onerror = (e: Event) => {
        console.error('Error retrieving canvas state:', e);
        db.close();
      };
    } catch (err) {
      console.error('Error restoring canvas state:', err);
    }
  };
}
onMounted(() => {
  // 当组件加载时，恢复状态
  restoreCanvasState();
});

/**
 * 清除画布状态
 */
function clearCanvasState() {
  if (window.indexedDB) {
    try {
      const request = window.indexedDB.open('canvasState', 1);
      request.onsuccess = (e: Event) => {
        const db = (e.target as IDBOpenDBRequest).result;
        const tx = db.transaction('canvasState', 'readwrite');
        const store = tx.objectStore('canvasState');
        store.delete(element.value.id || 'default_id');
        tx.oncomplete = () => {
          db.close();
        };
      };
    } catch (err) {
      console.error('Error clearing canvas state:', err);
    }
  }
}

// 监听页面卸载事件，用于检测页面刷新
window.addEventListener('beforeunload', () => {
  // 清除页面刷新标记
  sessionStorage.removeItem('is_page_refresh');
  // 页面刷新时清除画布状态
  clearCanvasState();
});
</script>

<template>
  <van-field
    :label="element.stem"
    :required="element.config.is_required === 1"
    label-align="top"
    :border="false"
    readonly
  >
    <template #left-icon> {{ isPreview ? element.title : index + 1 }}. </template>
    <template #label>
      <contenteditable
        v-model="element.stem"
        className="contenteditable-label"
        :active="active"
        @blur="emitValue"
        :errorMessage="errorMessage"
      ></contenteditable>
    </template>
    <template #input>
      <div class="sign-question">
        <canvas
          ref="signatureCanvas"
          :width="canvasWidth"
          :height="canvasHeight"
          style="border: 1px dashed #ccc; border-radius: 4px"
        >
        </canvas>
        <div class="sign-text" :class="{ show: true }">
          <span
            class="icon mobilefont mobilefont-qingkong"
            title="清空"
            @click="clearCanvas"
          ></span>
          <span class="icon mobilefont mobilefont-chexiao" @click="undo"></span>
          <span
            class="icon mobilefont"
            :class="isEraser ? 'mobilefont-huabi' : 'mobilefont-rubber'"
            @click="togglePen"
          ></span>
          <span class="icon mobilefont mobilefont-shangchuan" @click="handleUploadImg"></span>
        </div>
        <div class="sign-tips">请在空白区域书写您的签名</div>
      </div>
    </template>
  </van-field>
</template>

<style lang="scss" scoped>
.sign-question {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: center;
  width: 100%;
  padding: 10px 0;

  // canvas {
  //     width: 100%;
  //     touch-action: none;
  // }

  .sign-text {
    position: absolute;
    bottom: 0;
    left: 50%;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-around;
    width: 100%;
    color: #999;
    font-size: 14px;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s;
    transform: translate(-50%, -50%);

    &.show {
      opacity: 0.8;
      pointer-events: auto;
    }

    span {
      padding: 5px 10px;
      cursor: pointer;

      &:hover {
        color: #666;
      }
    }
  }

  .sign-tips {
    position: absolute;
    top: 50%;
    left: 50%;
    width: max-content;
    color: #cdcdcd;
    transform: translate(-50%, -50%);
  }
}
</style>
