<template>
  <view 
    :id="containerId"
    class="signature-container"
    :style="containerStyle"
  >
    <text v-if="placeholder" :style="placeholderStyle">{{ placeholder }}</text>
    <canvas
      class="signature-canvas"
      disable-scroll
      :id="id"
      :canvas-id="id"
      :style="canvasStyle"
      :width="canvasWidth"
      :height="canvasHeight"
      @touchstart.stop="handleTouchStart"
      @touchmove.stop="handleTouchMove"
      @touchend.stop="handleTouchEnd"
      @touchcancel.stop="handleTouchEnd"
      @mousedown.stop="handleMouseDown"
      @mousemove.stop="handleMouseMove"
      @mouseup.stop ="handleMouseUp"
    ></canvas>
  </view>
</template>

<script setup lang="ts">
import { ref, onMounted, type Ref, computed, getCurrentInstance, onBeforeUnmount, nextTick } from 'vue';
import { propGetThemeVar, useTheme } from '../theme/ThemeDefine';
import { RandomUtils, waitTimeOut } from '@imengyu/imengyu-utils';

const id = `signatureCanvas${RandomUtils.genNonDuplicateID(10)}`;
const containerId = `signatureContainer${RandomUtils.genNonDuplicateID(10)}`;

// 定义绘图相关类型
interface Point { x: number; y: number; }
interface Line { points: Point[]; color: string; width: number; }

export interface SignatureProps {
  innerStyle?: object;
  placeholderStyle?: object;
  backgroundColor?: string;
  lineColor?: string;
  lineWidth?: number;
  round?: boolean;
  border?: boolean;
  borderStyle?: string;
  borderWidth?: number;
  borderColor?: string;
  placeholder?: string;
}
export interface SignatureInstance {
  /** 
   * 清空签名 
   */
  clear: () => void;
  /** 
   * 设置签名图片 
   */
  setImage: (image: string) => void;
  /** 
   * 导出签名为图片 
   */
  export: () => Promise<string>;
}

const props = withDefaults(defineProps<SignatureProps>(), {
  backgroundColor: () => propGetThemeVar('SignatureBackgroundColor', 'white'),
  lineColor: () => propGetThemeVar('SignatureLineColor', 'black'),
  lineWidth: () => propGetThemeVar('SignatureLineWidth', 3),
  round: () => propGetThemeVar('SignatureRound', true),
  border: () => propGetThemeVar('SignatureBorder', true),
  borderWidth: () => propGetThemeVar('SignatureBorderWidth', 3),
  borderStyle: () => propGetThemeVar('SignatureBorderStyle', 'dashed'),
  borderColor: () => propGetThemeVar('SignatureBorderColor', 'border.signature'),
  placeholder: () => propGetThemeVar('SignaturePlaceholder', '请在虚线框内签名'),
});

const theme = useTheme();
const instance = getCurrentInstance();

const containerStyle = computed(() => ({
  backgroundColor: theme.resolveThemeColor(props.backgroundColor),
  borderRadius: props.round ? theme.resolveThemeSize('SignatureBorderRadius', 12) : '0',
  border: props.border ? 
    `${theme.resolveThemeSize(props.borderWidth)} ${props.borderStyle} ${theme.resolveThemeColor(props.borderColor)}`
    : 'none',
  ...props.innerStyle
}));
const placeholderStyle = computed(() => ({
  fontSize: theme.resolveThemeSize('SignaturePlaceholderFontSize', 26),
  color: theme.resolveThemeColor('SignaturePlaceholderColor', 'text.second'),
  ...props.placeholderStyle
}));
const canvasStyle = computed(() => ({
  width: `${canvasWidth.value}px`,
  height: `${canvasHeight.value}px`
}));

// 组件状态
const canvasContext: Ref<UniApp.CanvasContext | null> = ref(null);
const canvasWidth = ref(0);
const canvasHeight = ref(0);
const lines = ref<Line[]>([]);
const currentLine = ref<Line | null>(null);
const containerRect = ref<UniApp.NodeInfo>();
let timer = 0;
let isDrawing = false;
let absPos = [0,0];
let isDirty = true;
let isCreating = false;

async function initCanvas() {
  if (isCreating)
    return;
  isCreating = true;
  await waitTimeOut(100);
  // 获取容器尺寸信息
  containerRect.value = await new Promise<UniApp.NodeInfo>((resolve) => {
    uni.createSelectorQuery()
      .in(instance)
      .select(`#${containerId}`)
      .boundingClientRect(resolve as any)
      .exec();
  });

  if (containerRect.value) {
    canvasWidth.value = containerRect.value.width! - 2;
    canvasHeight.value = containerRect.value.height! - 2;
  }
  if (canvasWidth.value > 0 && canvasHeight.value > 0) {
    if (!canvasContext.value)
      // 创建Canvas上下文
      canvasContext.value = uni.createCanvasContext(id, instance);
  }
  isCreating = false;
}
function render() {
  if (canvasWidth.value <= 0 || canvasHeight.value <= 0) {
    initCanvas();
    return;
  }
  if (!canvasContext.value)
    return;
  if (!isDirty)
    return;
  isDirty = false;
  drawBackground();
  lines.value.forEach(drawLine);
  if (currentLine.value)
    drawLine(currentLine.value);
  canvasContext.value.draw();
}

function startDrag(x: number, y: number) {
  isDrawing = true;
  // 创建新线条
  currentLine.value = {
    points: [{ x, y }],
    color: props.lineColor || 'black',
    width: props.lineWidth || 3
  };
}
function doDrag(x: number, y: number) {
  if (!currentLine.value)
    return;
  currentLine.value.points.push({ x, y });
  isDirty = true;
}
function endDrag() {
  if (!isDrawing || !currentLine.value) 
    return;
  isDrawing = false;
  lines.value.push(currentLine.value);
  currentLine.value = null;
}

function handleTouchStart(e: any) {
  if (!canvasContext.value) return;   
  const { x, y } = e.touches[0];
  startDrag(x, y);
}
function handleTouchMove(e: any) {
  if (!isDrawing || !currentLine.value || !canvasContext.value) 
    return;
  const { x, y } = e.touches[0];
  doDrag(x, y);
}
function handleTouchEnd() {
  endDrag();
}

function handleMouseDown(e: any) {
  if (!canvasContext.value) 
    return;
  //H5鼠标事件需要减去canvas位置
  uni.createSelectorQuery()
    .in(instance)
    .select(`#${id}`)
    .boundingClientRect()
    .exec((res) => {
      if (res[0]) {
        const { clientX, clientY } = e.touches[0];
        absPos = [res[0].left, res[0].top];
        startDrag(clientX - res[0].left, clientY - res[0].top);
      }
    });
}
function handleMouseMove(e: any) {
  if (!isDrawing || !currentLine.value || !canvasContext.value) 
    return;
  const { clientX, clientY } = e.touches[0];
  doDrag(clientX - absPos[0], clientY - absPos[1]);
}
function handleMouseUp() {
  endDrag();
}

function drawBackground() {
  if (!canvasContext.value || !canvasWidth.value || !canvasHeight.value) return;
  const ctx = canvasContext.value;
  ctx.save();
  ctx.fillStyle = props.backgroundColor || 'white';
  ctx.fillRect(0, 0, canvasWidth.value, canvasHeight.value);
  ctx.restore();
}
function drawLine(line: Line) {
  if (!canvasContext.value || line.points.length < 2) 
    return;

  const ctx = canvasContext.value;
  ctx.strokeStyle = line.color;
  ctx.lineWidth = line.width;
  ctx.lineCap = 'round';
  ctx.lineJoin = 'round';

  ctx.beginPath();
  const firstPoint = line.points[0];
  ctx.moveTo(firstPoint.x, firstPoint.y);

  for (let i = 1; i < line.points.length; i++) {
    ctx.lineTo(line.points[i].x, line.points[i].y);
  }

  ctx.stroke();
}

function clear() {
  lines.value = [];
  currentLine.value = null;
  isDirty = true;
}
async function exportImage(): Promise<string> {
  if (!canvasWidth.value || !canvasHeight.value) {
    throw new Error('Canvas is not initialized');
  }
  return new Promise((resolve, reject) => {
    uni.canvasToTempFilePath({
      canvasId: id,
      width: canvasWidth.value,
      height: canvasHeight.value,
      destWidth: canvasWidth.value * 2,
      destHeight: canvasHeight.value * 2,
      quality: 1,
      success: (res) => resolve(res.tempFilePath),
      fail: (err) => reject(err)
    }, instance);
  });
}
function setImage(image: string) {
  if (!canvasContext.value) return;
  canvasContext.value.drawImage(image, 0, 0, canvasWidth.value, canvasHeight.value);
  isDirty = true;
}

onMounted(async () => {
  await nextTick();
  await initCanvas();
  timer = setInterval(render, 100) as any;
});
onBeforeUnmount(() => {
  clearInterval(timer);
  timer = 0;
});

defineExpose<SignatureInstance>({
  clear,
  export: exportImage,
  setImage
});
</script>

<style lang="scss">
.signature-container {
  width: 100%;
  height: 200px;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.signature-canvas {
  width: 100%;
  height: 100%;
}
</style>