<script lang="ts">
  import { solve } from '$lib/engine';
  import type { CalculatorDef } from '$lib/data/calculators';
  import { page } from '$app/stores';
  import { onDestroy, onMount } from 'svelte';
  import { browser } from '$app/environment';
  import { getConversionRateText } from '$lib/utils/conversionRate';
  import QuickDefinitionCard from '$lib/components/QuickDefinitionCard.svelte';
  import QuickConversionExample from '$lib/components/QuickConversionExample.svelte';
  import QuickConversionTable from '$lib/components/QuickConversionTable.svelte';

  export let config: CalculatorDef;
  export let showTitle = true;

  let val1 = '';
  let val2 = '';
  let val3 = '';
  let activeField: 1 | 2 | 3 = 1;
  let swapState: { originalField: 1 | 2; originalValue: string | number | null } | null = null;
  let copyStatus: 'idle' | 'copied' | 'failed' = 'idle';
  let statusTimeout: ReturnType<typeof setTimeout> | null = null;
  let tooltipFadeTimeout: ReturnType<typeof setTimeout> | null = null;
  let tooltipHideTimeout: ReturnType<typeof setTimeout> | null = null;
  let showCopyTooltip = false;
  let isTooltipFading = false;
  let showHoverTooltip = false;
  let footerControlsEl: HTMLDivElement | null = null;
  let tooltipX = 20;
  let copyStatusMessage = '';
  let initializedSlug: string | null = null;
  let conversionRateText: string | null = null;

  $: has3 = ['3col', '3col-mul'].includes(config.type) || !!config.labels.in3;
  $: isTextInput = ['base', 'text-bin', 'bin-text', 'dec-frac', 'dms-dd', 'dd-dms'].includes(config.type);
  $: conversionRateText = getConversionRateText(config);

  // Clear inputs only when navigating to a different calculator slug.
  $: if (config?.slug) {
    if (initializedSlug === null) {
      initializedSlug = config.slug;
    } else if (initializedSlug !== config.slug) {
      initializedSlug = config.slug;
      clear();
    }
  }

  function handleInput(source: 1 | 2 | 3, options?: { preserveSwap?: boolean }) {
    if (!options?.preserveSwap) {
      swapState = null;
    }
    activeField = source;
    const result = solve(config, source, val1, val2, val3);
    if (source !== 1) val1 = result.val1;
    if (source !== 2) val2 = result.val2;
    if (source !== 3) val3 = result.val3;
  }

  function swap() {
    if (!swapState) {
      const manualField: 1 | 2 = activeField === 1 ? 1 : 2;
      const manualValue = manualField === 1 ? val1 : val2;
      const targetField: 1 | 2 = manualField === 1 ? 2 : 1;
      swapState = { originalField: manualField, originalValue: manualValue };
      if (targetField === 1) val1 = manualValue;
      else val2 = manualValue;
      handleInput(targetField, { preserveSwap: true });
      return;
    }

    const manualField = swapState.originalField;
    const manualValue = swapState.originalValue === null ? '' : String(swapState.originalValue);
    if (manualField === 1) val1 = manualValue;
    else val2 = manualValue;
    swapState = null;
    handleInput(manualField, { preserveSwap: true });
  }

  function clear() {
    val1 = '';
    val2 = '';
    val3 = '';
    swapState = null;
  }

  function buildShareUrl() {
    const params = new URLSearchParams();
    const v1 = toQueryValue(val1);
    const v2 = toQueryValue(val2);
    const v3 = toQueryValue(val3);
    const source: 1 | 2 | 3 = has3 ? activeField : (activeField === 2 ? 2 : 1);

    if (!has3) {
      const sourceValue = source === 1 ? v1 : v2;
      if (sourceValue !== null) {
        params.set(source === 1 ? 'v1' : 'v2', sourceValue);
      }
    } else if (source === 3) {
      if (v2 !== null) params.set('v2', v2);
      if (v3 !== null) params.set('v3', v3);
    } else {
      if (v1 !== null) params.set('v1', v1);
      if (v2 !== null) params.set('v2', v2);
    }

    const shareUrl = new URL($page.url);
    shareUrl.search = params.toString();
    return shareUrl.toString();
  }

  function toQueryValue(value: unknown): string | null {
    if (value === null || value === undefined) {
      return null;
    }
    const stringValue = String(value);
    return stringValue.trim() ? stringValue : null;
  }

  async function copyText(text: string) {
    if (navigator.clipboard?.writeText) {
      await navigator.clipboard.writeText(text);
      return;
    }

    const textArea = document.createElement('textarea');
    textArea.value = text;
    textArea.setAttribute('readonly', '');
    textArea.style.position = 'absolute';
    textArea.style.left = '-9999px';
    document.body.appendChild(textArea);
    textArea.select();

    const copied = document.execCommand('copy');
    document.body.removeChild(textArea);
    if (!copied) {
      throw new Error('execCommand copy failed');
    }
  }

  function triggerCopyTooltip() {
    if (tooltipFadeTimeout) clearTimeout(tooltipFadeTimeout);
    if (tooltipHideTimeout) clearTimeout(tooltipHideTimeout);
    showCopyTooltip = true;
    isTooltipFading = false;
    tooltipFadeTimeout = setTimeout(() => {
      isTooltipFading = true;
    }, 900);
    tooltipHideTimeout = setTimeout(() => {
      showCopyTooltip = false;
      isTooltipFading = false;
    }, 1300);
  }

  function updateTooltipPosition(event: MouseEvent) {
    if (!footerControlsEl) return;
    const rect = footerControlsEl.getBoundingClientRect();
    const x = event.clientX - rect.left;
    tooltipX = Math.max(12, Math.min(rect.width - 12, x));
  }

  function positionTooltipFromButton(button: HTMLButtonElement) {
    if (!footerControlsEl) return;
    const controlsRect = footerControlsEl.getBoundingClientRect();
    const buttonRect = button.getBoundingClientRect();
    const centerX = buttonRect.left - controlsRect.left + buttonRect.width / 2;
    tooltipX = Math.max(12, Math.min(controlsRect.width - 12, centerX));
  }

  async function copyLink() {
    if (!browser) return;
    const url = buildShareUrl();

    try {
      await copyText(url);
      copyStatus = 'copied';
      triggerCopyTooltip();
    } catch (error) {
      console.error('Failed to copy link', error);
      copyStatus = 'failed';
    } finally {
      if (statusTimeout) {
        clearTimeout(statusTimeout);
      }
      statusTimeout = setTimeout(() => {
        copyStatus = 'idle';
      }, 2000);
    }
  }

  $: copyStatusMessage =
    copyStatus === 'copied'
      ? 'Link copied to clipboard'
      : copyStatus === 'failed'
        ? 'Failed to copy link'
        : '';

  onMount(() => {
    const params = new URLSearchParams($page.url.search);
    const hasV1 = params.has('v1');
    const hasV2 = params.has('v2');
    const hasV3 = has3 && params.has('v3');

    if (has3 && hasV2 && hasV3) {
      val2 = params.get('v2') ?? '';
      val3 = params.get('v3') ?? '';
      handleInput(3);
    } else if (has3 && hasV1 && hasV2) {
      val1 = params.get('v1') ?? '';
      val2 = params.get('v2') ?? '';
      handleInput(1);
    } else if (hasV1) {
      val1 = params.get('v1') ?? '';
      handleInput(1);
    } else if (hasV2) {
      val2 = params.get('v2') ?? '';
      handleInput(2);
    } else if (hasV3) {
      val3 = params.get('v3') ?? '';
      handleInput(3);
    }
  });

  onDestroy(() => {
    if (statusTimeout) clearTimeout(statusTimeout);
    if (tooltipFadeTimeout) clearTimeout(tooltipFadeTimeout);
    if (tooltipHideTimeout) clearTimeout(tooltipHideTimeout);
  });
</script>

<div class="calculator-card">
  {#if showTitle || config.teaser}
    <div class="calc-header">
      {#if showTitle}
        <h2>{config.name}</h2>
      {/if}
      {#if config.teaser}
        <p class="calc-subtitle" class:no-title={!showTitle}>{config.teaser}</p>
      {/if}
    </div>
  {/if}

  <div class="calc-body" class:three-col={has3}>
    <div class="input-group">
      <label for="calc-in1">{config.labels.in1}</label>
      <input
        id="calc-in1"
        type={isTextInput ? 'text' : 'number'}
        bind:value={val1}
        on:input={() => handleInput(1)}
        placeholder="Enter value"
        class:active={activeField === 1}
      />
    </div>

    {#if !has3}
      <div class="swap-col">
        <button
          type="button"
          class="swap-btn"
          on:click={swap}
          title="Swap values"
          aria-label="Swap conversion direction"
        >
          <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <path d="M7 16l-4-4 4-4M17 8l4 4-4 4M3 12h18" />
          </svg>
        </button>
      </div>
    {/if}

    <div class="input-group">
      <label for="calc-in2">{config.labels.in2}</label>
      <input
        id="calc-in2"
        type={isTextInput ? 'text' : 'number'}
        bind:value={val2}
        on:input={() => handleInput(2)}
        placeholder={has3 ? 'Enter value' : 'Result'}
        class:active={activeField === 2}
      />
    </div>

    {#if has3}
      <div class="input-group result-group">
        <label for="calc-in3">{config.labels.in3}</label>
        <input
          id="calc-in3"
          type="number"
          bind:value={val3}
          on:input={() => handleInput(3)}
          placeholder="Result"
          class:active={activeField === 3}
        />
      </div>
    {/if}
  </div>

  <div class="calc-footer">
    <div class="footer-controls" bind:this={footerControlsEl}>
      <button type="button" class="clear-btn" on:click={clear} aria-label="Clear calculator inputs">
        Clear
      </button>
      <button
        type="button"
        class="icon-btn"
        on:click={(event) => {
          positionTooltipFromButton(event.currentTarget as HTMLButtonElement);
          copyLink();
        }}
        on:mouseenter={(event) => {
          showHoverTooltip = true;
          updateTooltipPosition(event);
        }}
        on:mousemove={updateTooltipPosition}
        on:mouseleave={() => (showHoverTooltip = false)}
        on:focus={(event) => {
          showHoverTooltip = true;
          positionTooltipFromButton(event.currentTarget as HTMLButtonElement);
        }}
        on:blur={() => (showHoverTooltip = false)}
        aria-label="Copy calculator link"
      >
        <svg viewBox="0 0 24 24" role="presentation" aria-hidden="true">
          <path
            d="M13.5 6.5l1.5-1.5a4.243 4.243 0 0 1 6 6L19.5 12.5M10.5 17.5L9 19a4.243 4.243 0 1 1-6-6L4.5 11.5M8 16l8-8"
            fill="none"
            stroke="currentColor"
            stroke-width="1.9"
            stroke-linecap="round"
            stroke-linejoin="round"
          />
        </svg>
      </button>
      {#if showHoverTooltip && !showCopyTooltip}
        <span class="copy-tooltip hover" style={`left: ${tooltipX}px;`}>Copy link</span>
      {/if}
      {#if showCopyTooltip && copyStatus === 'copied'}
        <span class="copy-tooltip" class:fading={isTooltipFading} style={`left: ${tooltipX}px;`}>Link copied!</span>
      {/if}
      <span class="sr-only" aria-live="polite">
        {copyStatusMessage}
      </span>
    </div>
    {#if conversionRateText}
      <span class="formula-hint">
        {conversionRateText}
      </span>
    {/if}
  </div>
  <QuickConversionTable {config} />
  <QuickConversionExample {config} />
  <QuickDefinitionCard {config} />
</div>

<style>
  .calculator-card {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 16px;
    overflow: hidden;
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
    transition: box-shadow 0.3s ease;
  }
  .calculator-card:hover {
    box-shadow: 0 12px 48px rgba(0, 0, 0, 0.18);
  }

  .calc-header {
    padding: 1.5rem 2rem 1rem;
    border-bottom: 1px solid var(--border);
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-dark) 100%);
  }
  .calc-header h2 {
    margin: 0;
    font-size: 1.25rem;
    font-weight: 600;
    color: #fff;
    letter-spacing: -0.01em;
  }
  .calc-subtitle {
    margin: 0.35rem 0 0;
    font-size: 0.9rem;
    color: rgba(255, 255, 255, 0.85);
    font-weight: 400;
  }
  .calc-subtitle.no-title {
    margin-top: 0;
  }

  .calc-body {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    gap: 1rem;
    padding: 2rem;
    align-items: end;
  }
  .calc-body.three-col {
    grid-template-columns: 1fr 1fr 1fr;
  }

  .input-group {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }
  .input-group label {
    font-size: 0.8rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
  }
  .input-group input {
    padding: 0.85rem 1rem;
    border: 2px solid var(--border);
    border-radius: 10px;
    background: var(--input-bg);
    color: var(--text);
    font-family: 'JetBrains Mono', monospace;
    font-size: 1.1rem;
    transition: border-color 0.2s, box-shadow 0.2s;
    width: 100%;
    box-sizing: border-box;
  }
  .input-group input:focus,
  .input-group input.active {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-glow);
  }
  .input-group input::placeholder {
    color: var(--text-muted);
    opacity: 0.5;
  }

  /* Hide number spinners */
  .input-group input[type='number']::-webkit-inner-spin-button,
  .input-group input[type='number']::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
  }
  .input-group input[type='number'] {
    appearance: textfield;
    -moz-appearance: textfield;
  }

  .swap-col {
    display: flex;
    align-items: center;
    justify-content: center;
    padding-top: 1.2rem;
  }
  .swap-btn {
    background: var(--accent);
    color: #fff;
    border: none;
    border-radius: 50%;
    width: 44px;
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: transform 0.2s, background 0.2s;
  }
  .swap-btn:hover {
    background: var(--accent-dark);
    transform: rotate(180deg);
  }
  .swap-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--accent-glow);
  }

  .calc-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem 2rem 1.25rem;
    border-top: 1px solid var(--border);
  }
  .footer-controls {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    position: relative;
  }

  .clear-btn {
    padding: 0.5rem 1.25rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: transparent;
    color: var(--text-muted);
    font-size: 0.85rem;
    cursor: pointer;
    transition: background 0.2s, color 0.2s;
  }
  .clear-btn:hover {
    background: var(--accent);
    color: #fff;
    border-color: var(--accent);
  }
  .clear-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--accent-glow);
  }
  .icon-btn {
    width: 40px;
    height: 40px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--section-bg);
    color: var(--text);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    cursor: pointer;
    transition: background 0.2s, border-color 0.2s;
  }
  .icon-btn svg {
    width: 1.1rem;
    height: 1.1rem;
  }
  .icon-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }
  .icon-btn:not(:disabled):hover {
    border-color: var(--accent);
    background: var(--surface-hover);
  }
  .copy-tooltip {
    position: absolute;
    bottom: calc(100% + 0.4rem);
    background: color-mix(in srgb, var(--accent) 90%, black 10%);
    color: #fff;
    border-radius: 6px;
    padding: 0.35rem 0.55rem;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    pointer-events: none;
    opacity: 1;
    transform: translate(-50%, 0);
    transition: opacity 0.35s ease, transform 0.35s ease;
    white-space: nowrap;
    z-index: 2;
  }
  .copy-tooltip.hover {
    background: var(--section-bg);
    color: var(--text);
    border: 1px solid var(--border);
  }
  .copy-tooltip.fading {
    opacity: 0;
    transform: translate(-50%, -0.2rem);
  }
  .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
  .formula-hint {
    font-size: 0.78rem;
    color: var(--text-muted);
    font-family: 'JetBrains Mono', monospace;
  }

  @media (max-width: 900px) {
    .calc-footer {
      flex-wrap: wrap;
      gap: 0.75rem;
    }
    .formula-hint {
      width: 100%;
    }
  }

  @media (max-width: 640px) {
    .calc-header {
      padding: 1.2rem 1.2rem 0.9rem;
    }
    .calc-body {
      grid-template-columns: 1fr;
      gap: 0.75rem;
      padding: 1.25rem;
    }
    .calc-body.three-col {
      grid-template-columns: 1fr;
    }
    .swap-col {
      padding-top: 0;
    }
    .swap-btn {
      transform: rotate(90deg);
    }
    .swap-btn:hover {
      transform: rotate(270deg);
    }
    .calc-footer {
      padding: 0.9rem 1.25rem 1rem;
    }
  }
</style>
