<script lang="ts">
  import { onMount } from 'svelte';

  export let value = '';
  export let disabled = false;

  let canvas: HTMLCanvasElement;
  let isDrawing = false;
  let hasSigned = false;
  let activePointerId: number | null = null;
  let lines: { x: number; y: number }[][] = [];

  function resizeCanvas() {
    if (!canvas) return;

    const ratio = Math.max(window.devicePixelRatio || 1, 1);
    const rect = canvas.getBoundingClientRect();
    canvas.width = Math.max(1, Math.round(rect.width * ratio));
    canvas.height = Math.max(1, Math.round(rect.height * ratio));

    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
    drawAllLines();
    syncValue();
  }

  function getContext() {
    return canvas?.getContext('2d') ?? null;
  }

  function drawAllLines() {
    const ctx = getContext();
    if (!ctx || !canvas) return;

    const width = canvas.width / Math.max(window.devicePixelRatio || 1, 1);
    const height = canvas.height / Math.max(window.devicePixelRatio || 1, 1);

    ctx.clearRect(0, 0, width, height);
    ctx.lineCap = 'round';
    ctx.lineJoin = 'round';
    ctx.strokeStyle = '#213021';
    ctx.lineWidth = 3;

    for (const line of lines) {
      if (!line.length) continue;

      ctx.beginPath();
      ctx.moveTo(line[0].x, line[0].y);

      if (line.length === 1) {
        ctx.lineTo(line[0].x + 0.01, line[0].y + 0.01);
      } else {
        for (const point of line.slice(1)) {
          ctx.lineTo(point.x, point.y);
        }
      }

      ctx.stroke();
    }
  }

  function pointFromEvent(event: PointerEvent) {
    const rect = canvas.getBoundingClientRect();

    return {
      x: event.clientX - rect.left,
      y: event.clientY - rect.top
    };
  }

  function syncValue() {
    value = hasSigned && canvas ? canvas.toDataURL('image/png') : '';
  }

  function startDrawing(event: PointerEvent) {
    if (disabled) return;

    activePointerId = event.pointerId;
    isDrawing = true;
    canvas.setPointerCapture(event.pointerId);
    const point = pointFromEvent(event);
    lines = [...lines, [point]];
    hasSigned = true;
    drawAllLines();
    syncValue();
  }

  function continueDrawing(event: PointerEvent) {
    if (!isDrawing || disabled || activePointerId !== event.pointerId) return;

    const point = pointFromEvent(event);
    const nextLines = [...lines];
    const currentLine = nextLines[nextLines.length - 1];

    if (!currentLine) return;

    currentLine.push(point);
    lines = nextLines;
    drawAllLines();
    syncValue();
  }

  function stopDrawing(event?: PointerEvent) {
    if (event && activePointerId === event.pointerId && canvas.hasPointerCapture(event.pointerId)) {
      canvas.releasePointerCapture(event.pointerId);
    }

    activePointerId = null;
    isDrawing = false;
    syncValue();
  }

  export function clear() {
    lines = [];
    hasSigned = false;
    drawAllLines();
    syncValue();
  }

  onMount(() => {
    resizeCanvas();
    window.addEventListener('resize', resizeCanvas);

    return () => {
      window.removeEventListener('resize', resizeCanvas);
    };
  });
</script>

<div class:signature-disabled={disabled} class="signature-shell">
  <canvas
    bind:this={canvas}
    class="signature-canvas"
    aria-label="Draw your signature"
    on:pointerdown={startDrawing}
    on:pointermove={continueDrawing}
    on:pointerup={stopDrawing}
    on:pointerleave={stopDrawing}
    on:pointercancel={stopDrawing}
  ></canvas>
  {#if !value}
    <div class="signature-hint" aria-hidden="true">Sign here</div>
  {/if}
</div>

<style>
  .signature-shell {
    position: relative;
    width: 100%;
    min-height: 180px;
    border-radius: 18px;
    background: #fff;
    overflow: hidden;
  }

  .signature-shell.signature-disabled {
    opacity: 0.7;
  }

  .signature-canvas {
    display: block;
    width: 100%;
    height: 180px;
    touch-action: none;
    cursor: crosshair;
  }

  .signature-disabled .signature-canvas {
    cursor: not-allowed;
  }

  .signature-hint {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-head);
    font-size: 24px;
    color: rgba(33, 48, 33, 0.22);
    pointer-events: none;
  }

  @media (max-width: 768px) {
    .signature-shell {
      min-height: 160px;
    }

    .signature-canvas {
      height: 160px;
    }

    .signature-hint {
      font-size: 21px;
    }
  }
</style>
