<!--
  Numeric PIN entry.

  Presentation only: it collects digits and hands them up. It does not know the
  PIN, does not compare anything, and does not count attempts — the backend
  returns an `UnlockOutcome` and this renders whatever it says. A pad that could
  decide would be a lock the webview could pick.

  Sized for a living room: large targets, usable with a remote's arrow keys as
  well as a touchscreen.

  TRACES: UR-083 | DR-276
-->
<script lang="ts">
  interface Props {
    /** Digits entered so far. */
    value: string;
    /** Message under the dots — wrong PIN, lockout, etc. */
    error?: string | null;
    /** Blocks input while an attempt is in flight or the profile is locked out. */
    disabled?: boolean;
    maxLength?: number;
    onsubmit: (pin: string) => void;
    oncancel: () => void;
  }

  let {
    value = $bindable(),
    error = null,
    disabled = false,
    maxLength = 8,
    onsubmit,
    oncancel,
  }: Props = $props();

  const KEYS = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "", "0", "⌫"];

  function press(key: string) {
    if (disabled) return;
    if (key === "⌫") {
      value = value.slice(0, -1);
    } else if (key && value.length < maxLength) {
      value = value + key;
    }
  }

  function handleKeydown(event: KeyboardEvent) {
    if (disabled) return;
    if (/^[0-9]$/.test(event.key)) {
      event.preventDefault();
      press(event.key);
    } else if (event.key === "Backspace") {
      event.preventDefault();
      press("⌫");
    } else if (event.key === "Enter" && value.length >= 4) {
      event.preventDefault();
      onsubmit(value);
    } else if (event.key === "Escape") {
      event.preventDefault();
      oncancel();
    }
  }
</script>

<svelte:window onkeydown={handleKeydown} />

<div class="flex flex-col items-center gap-6">
  <!-- Entered digits, shown as dots. -->
  <div class="flex gap-3 h-4 items-center" aria-live="polite" aria-label="PIN entry">
    {#each Array(Math.max(value.length, 4)) as _, i (i)}
      <div
        class="rounded-full transition-all {i < value.length
          ? 'w-3 h-3 bg-white'
          : 'w-3 h-3 bg-gray-600'}"
      ></div>
    {/each}
  </div>

  {#if error}
    <p class="text-red-400 text-sm text-center max-w-xs" role="alert">{error}</p>
  {/if}

  <div class="grid grid-cols-3 gap-3">
    {#each KEYS as key (key)}
      {#if key === ""}
        <div></div>
      {:else}
        <button
          type="button"
          onclick={() => press(key)}
          {disabled}
          class="w-18 h-18 min-w-[4.5rem] min-h-[4.5rem] rounded-full bg-[var(--color-surface)] hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-[var(--color-jellyfin)] disabled:opacity-40 disabled:cursor-not-allowed text-2xl font-light transition-colors"
          aria-label={key === "⌫" ? "Delete" : key}
        >
          {key}
        </button>
      {/if}
    {/each}
  </div>

  <div class="flex gap-3 w-full max-w-xs">
    <button
      type="button"
      onclick={oncancel}
      class="flex-1 py-3 rounded-lg border border-gray-700 hover:bg-[var(--color-surface)] transition-colors"
    >
      Cancel
    </button>
    <button
      type="button"
      onclick={() => onsubmit(value)}
      disabled={disabled || value.length < 4}
      class="flex-1 py-3 rounded-lg bg-[var(--color-jellyfin)] hover:bg-[var(--color-jellyfin-dark)] disabled:opacity-50 disabled:cursor-not-allowed font-medium transition-colors"
    >
      Unlock
    </button>
  </div>
</div>
