<script lang="ts">
  import { tick, type Snippet } from "svelte";
  import type { Tab } from "../state/session.svelte.ts";

  type Props = {
    activeId: string;
    extras?: Snippet<[{ tab: Tab }]>;
    onAdd: () => void;
    onClose: (id: string) => void;
    onRename: (id: string, title: string) => void;
    onSelect: (id: string) => void;
    tabs: Tab[];
  };

  let { activeId, extras, onAdd, onClose, onRename, onSelect, tabs }: Props = $props();

  let editingId = $state<string | null>(null);
  let draft = $state<string>("");
  let inputEl = $state<HTMLInputElement | null>(null);

  async function startEditing(tab: Tab) {
    editingId = tab.id;
    draft = tab.title;
    await tick();
    inputEl?.select();
  }

  function commit() {
    if (editingId === null) return;
    onRename(editingId, draft);
    editingId = null;
    draft = "";
  }

  function cancel() {
    editingId = null;
    draft = "";
  }

  function onKeydown(event: KeyboardEvent) {
    if (event.key === "Enter") {
      event.preventDefault();
      commit();
    } else if (event.key === "Escape") {
      event.preventDefault();
      cancel();
    }
  }

  function handleClose(event: MouseEvent, id: string) {
    event.stopPropagation();
    onClose(id);
  }
</script>

<style lang="scss">
  .tabbar {
    align-items: stretch;
    background: var(--graphiql-panel, #252526);
    border-bottom: 1px solid var(--graphiql-border, #333);
    display: flex;
    font-size: 0.8125rem;
    min-height: 2rem;
    overflow-x: auto;
  }

  .tab {
    align-items: center;
    background: transparent;
    border: none;
    border-right: 1px solid var(--graphiql-border, #333);
    color: var(--graphiql-muted, #858585);
    cursor: pointer;
    display: flex;
    gap: 0.5rem;
    padding: 0 0.75rem;

    &.active {
      background: var(--graphiql-bg, #1e1e1e);
      color: var(--graphiql-fg, #d4d4d4);
    }

    &:hover:not(.active) {
      color: var(--graphiql-fg, #d4d4d4);
    }
  }

  .title {
    white-space: nowrap;
  }

  .edit {
    background: var(--graphiql-bg, #1e1e1e);
    border: 1px solid var(--graphiql-accent, #0e639c);
    border-radius: 2px;
    color: var(--graphiql-fg, #d4d4d4);
    font-family: inherit;
    font-size: inherit;
    min-width: 6rem;
    outline: none;
    padding: 0.125rem 0.25rem;
  }

  .close {
    background: none;
    border: none;
    color: inherit;
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    opacity: 0.6;
    padding: 0;

    &:hover {
      opacity: 1;
    }
  }

  .add {
    background: none;
    border: none;
    color: var(--graphiql-muted, #858585);
    cursor: pointer;
    font-size: 1rem;
    padding: 0 0.75rem;

    &:hover {
      color: var(--graphiql-fg, #d4d4d4);
    }
  }
</style>

<div class="tabbar" role="tablist">
  {#each tabs as tab (tab.id)}
    <div
      aria-selected={tab.id === activeId}
      class="tab"
      class:active={tab.id === activeId}
      ondblclick={() => startEditing(tab)}
      onclick={() => onSelect(tab.id)}
      onkeydown={(e) => {
        if (e.key === "Enter" || e.key === " ") {
          e.preventDefault();
          onSelect(tab.id);
        }
      }}
      role="tab"
      tabindex="0"
    >
      {#if editingId === tab.id}
        <input
          bind:this={inputEl}
          bind:value={draft}
          class="edit"
          onblur={commit}
          onclick={(e) => e.stopPropagation()}
          onkeydown={onKeydown}
          type="text"
        />
      {:else}
        <span class="title">{tab.title}</span>
      {/if}
      {#if extras}{@render extras({ tab })}{/if}
      <button
        aria-label="Close tab"
        class="close"
        onclick={(e) => handleClose(e, tab.id)}
      >×</button>
    </div>
  {/each}
  <button aria-label="New tab" class="add" onclick={onAdd}>+</button>
</div>
