<script lang="ts">
  import { appRpc } from './rpc.ts';

  // ── Types ────────────────────────────────────────────────────────────

  interface Task {
    id: string;
    title: string;
    description: string;
    status: string;
    priority: string;
    assignedTo: string | null;
    createdBy: string;
    groupId: string;
    version: number;
  }

  interface Props {
    groupId: string;
    /** Agent ID perspective for creating tasks (defaults to 'admin'). */
    agentId?: string;
  }

  let { groupId, agentId = 'admin' }: Props = $props();

  // ── State ────────────────────────────────────────────────────────────

  const COLUMNS = ['todo', 'progress', 'review', 'done', 'blocked'] as const;
  const COL_LABELS: Record<string, string> = {
    todo: 'To Do', progress: 'In Progress', review: 'Review',
    done: 'Done', blocked: 'Blocked',
  };
  const PRIORITY_COLORS: Record<string, string> = {
    high: 'var(--ctp-red)', medium: 'var(--ctp-peach)',
    low: 'var(--ctp-teal)',
  };

  let tasks = $state<Task[]>([]);
  let showCreateForm = $state(false);
  let newTitle = $state('');
  let newDesc = $state('');
  let newPriority = $state('medium');
  let error = $state('');

  // Drag state
  let draggedTaskId = $state<string | null>(null);
  let dragOverCol = $state<string | null>(null);

  // ── Derived ──────────────────────────────────────────────────────────

  let tasksByCol = $derived(
    COLUMNS.reduce((acc, col) => {
      acc[col] = tasks.filter(t => t.status === col);
      return acc;
    }, {} as Record<string, Task[]>)
  );

  // ── Data fetching ────────────────────────────────────────────────────

  async function loadTasks() {
    try {
      const res = await appRpc.request['bttask.listTasks']({ groupId });
      tasks = res.tasks;
    } catch (err) {
      console.error('[TaskBoard] loadTasks:', err);
    }
  }

  async function createTask() {
    const title = newTitle.trim();
    if (!title) { error = 'Title required'; return; }
    error = '';

    try {
      const res = await appRpc.request['bttask.createTask']({
        title,
        description: newDesc.trim(),
        priority: newPriority,
        groupId,
        createdBy: agentId,
      });
      if (res.ok) {
        newTitle = '';
        newDesc = '';
        newPriority = 'medium';
        showCreateForm = false;
        await loadTasks();
      } else {
        error = res.error ?? 'Failed to create task';
      }
    } catch (err) {
      console.error('[TaskBoard] createTask:', err);
      error = 'Failed to create task';
    }
  }

  async function moveTask(taskId: string, newStatus: string) {
    const task = tasks.find(t => t.id === taskId);
    if (!task || task.status === newStatus) return;

    try {
      const res = await appRpc.request['bttask.updateTaskStatus']({
        taskId,
        status: newStatus,
        expectedVersion: task.version,
      });
      if (res.ok) {
        // Optimistic update
        task.status = newStatus;
        task.version = res.newVersion ?? task.version + 1;
        tasks = [...tasks]; // trigger reactivity
      } else {
        error = res.error ?? 'Version conflict';
        await loadTasks(); // reload on conflict
      }
    } catch (err) {
      console.error('[TaskBoard] moveTask:', err);
      await loadTasks();
    }
  }

  async function deleteTask(taskId: string) {
    try {
      await appRpc.request['bttask.deleteTask']({ taskId });
      tasks = tasks.filter(t => t.id !== taskId);
    } catch (err) {
      console.error('[TaskBoard] deleteTask:', err);
    }
  }

  // ── Drag handlers ────────────────────────────────────────────────────

  function onDragStart(e: DragEvent, taskId: string) {
    draggedTaskId = taskId;
    if (e.dataTransfer) {
      e.dataTransfer.effectAllowed = 'move';
      e.dataTransfer.setData('text/plain', taskId);
    }
  }

  function onDragOver(e: DragEvent, col: string) {
    e.preventDefault();
    dragOverCol = col;
  }

  function onDragLeave() {
    dragOverCol = null;
  }

  function onDrop(e: DragEvent, col: string) {
    e.preventDefault();
    dragOverCol = null;
    if (draggedTaskId) {
      moveTask(draggedTaskId, col);
      draggedTaskId = null;
    }
  }

  function onDragEnd() {
    draggedTaskId = null;
    dragOverCol = null;
  }

  // ── Init + polling ───────────────────────────────────────────────────

  let pollTimer: ReturnType<typeof setInterval> | null = null;

  $effect(() => {
    loadTasks();
    pollTimer = setInterval(loadTasks, 5000);
    return () => { if (pollTimer) clearInterval(pollTimer); };
  });
</script>

<div class="task-board">
  <!-- Toolbar -->
  <div class="tb-toolbar">
    <span class="tb-title">Task Board</span>
    <span class="tb-count">{tasks.length} tasks</span>
    <button class="tb-add-btn" onclick={() => { showCreateForm = !showCreateForm; }}>
      {showCreateForm ? 'Cancel' : '+ Task'}
    </button>
  </div>

  <!-- Create form -->
  {#if showCreateForm}
    <div class="tb-create-form">
      <input
        class="tb-input"
        type="text"
        placeholder="Task title"
        bind:value={newTitle}
        onkeydown={(e) => { if (e.key === 'Enter') createTask(); }}
      />
      <input
        class="tb-input tb-desc"
        type="text"
        placeholder="Description (optional)"
        bind:value={newDesc}
      />
      <div class="tb-form-row">
        <select class="tb-select" bind:value={newPriority}>
          <option value="low">Low</option>
          <option value="medium">Medium</option>
          <option value="high">High</option>
        </select>
        <button class="tb-submit" onclick={createTask}>Create</button>
      </div>
      {#if error}
        <span class="tb-error">{error}</span>
      {/if}
    </div>
  {/if}

  <!-- Kanban columns -->
  <div class="tb-columns">
    {#each COLUMNS as col}
      <div
        class="tb-column"
        class:drag-over={dragOverCol === col}
        ondragover={(e) => onDragOver(e, col)}
        ondragleave={onDragLeave}
        ondrop={(e) => onDrop(e, col)}
        role="list"
        aria-label="{COL_LABELS[col]} column"
      >
        <div class="tb-col-header">
          <span class="tb-col-label">{COL_LABELS[col]}</span>
          <span class="tb-col-count">{tasksByCol[col]?.length ?? 0}</span>
        </div>

        <div class="tb-col-body">
          {#each tasksByCol[col] ?? [] as task (task.id)}
            <div
              class="tb-card"
              class:dragging={draggedTaskId === task.id}
              draggable="true"
              ondragstart={(e) => onDragStart(e, task.id)}
              ondragend={onDragEnd}
              role="listitem"
            >
              <div class="card-header">
                <span
                  class="priority-dot"
                  style:background={PRIORITY_COLORS[task.priority] ?? 'var(--ctp-overlay0)'}
                  title="Priority: {task.priority}"
                ></span>
                <span class="card-title">{task.title}</span>
                <button
                  class="card-delete"
                  onclick={() => deleteTask(task.id)}
                  title="Delete task"
                  aria-label="Delete task"
                >&times;</button>
              </div>
              {#if task.description}
                <div class="card-desc">{task.description}</div>
              {/if}
              {#if task.assignedTo}
                <div class="card-assignee">
                  <span class="assignee-icon">@</span>
                  {task.assignedTo}
                </div>
              {/if}
            </div>
          {/each}
        </div>
      </div>
    {/each}
  </div>
</div>

<style>
  .task-board {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    overflow: hidden;
  }

  .tb-toolbar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.375rem 0.625rem;
    background: var(--ctp-mantle);
    border-bottom: 1px solid var(--ctp-surface0);
    flex-shrink: 0;
  }

  .tb-title {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--ctp-text);
  }

  .tb-count {
    font-size: 0.6875rem;
    color: var(--ctp-overlay0);
    margin-left: auto;
  }

  .tb-add-btn {
    padding: 0.125rem 0.5rem;
    background: color-mix(in srgb, var(--ctp-green) 15%, transparent);
    border: 1px solid var(--ctp-green);
    border-radius: 0.25rem;
    color: var(--ctp-green);
    font-family: var(--ui-font-family);
    font-size: 0.6875rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.1s;
  }

  .tb-add-btn:hover {
    background: color-mix(in srgb, var(--ctp-green) 30%, transparent);
  }

  .tb-create-form {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    padding: 0.5rem 0.625rem;
    background: var(--ctp-mantle);
    border-bottom: 1px solid var(--ctp-surface0);
    flex-shrink: 0;
  }

  .tb-input {
    height: 1.625rem;
    background: var(--ctp-surface0);
    border: 1px solid var(--ctp-surface1);
    border-radius: 0.25rem;
    color: var(--ctp-text);
    font-family: var(--ui-font-family);
    font-size: 0.75rem;
    padding: 0 0.375rem;
    outline: none;
  }

  .tb-input:focus { border-color: var(--ctp-mauve); }

  .tb-form-row {
    display: flex;
    gap: 0.25rem;
    align-items: center;
  }

  .tb-select {
    height: 1.625rem;
    background: var(--ctp-surface0);
    border: 1px solid var(--ctp-surface1);
    border-radius: 0.25rem;
    color: var(--ctp-text);
    font-family: var(--ui-font-family);
    font-size: 0.6875rem;
    padding: 0 0.25rem;
    outline: none;
  }

  .tb-submit {
    padding: 0.125rem 0.625rem;
    height: 1.625rem;
    background: color-mix(in srgb, var(--ctp-mauve) 20%, transparent);
    border: 1px solid var(--ctp-mauve);
    border-radius: 0.25rem;
    color: var(--ctp-mauve);
    font-family: var(--ui-font-family);
    font-size: 0.6875rem;
    font-weight: 600;
    cursor: pointer;
    margin-left: auto;
  }

  .tb-submit:hover {
    background: color-mix(in srgb, var(--ctp-mauve) 35%, transparent);
  }

  .tb-error {
    font-size: 0.6875rem;
    color: var(--ctp-red);
  }

  .tb-columns {
    display: flex;
    flex: 1;
    min-height: 0;
    overflow-x: auto;
    gap: 1px;
    background: var(--ctp-surface0);
  }

  .tb-column {
    flex: 1;
    min-width: 8rem;
    display: flex;
    flex-direction: column;
    background: var(--ctp-base);
    transition: background 0.15s;
  }

  .tb-column.drag-over {
    background: color-mix(in srgb, var(--ctp-blue) 8%, var(--ctp-base));
  }

  .tb-col-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.375rem 0.5rem;
    border-bottom: 1px solid var(--ctp-surface0);
    flex-shrink: 0;
  }

  .tb-col-label {
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--ctp-subtext0);
  }

  .tb-col-count {
    font-size: 0.625rem;
    color: var(--ctp-overlay0);
    background: var(--ctp-surface0);
    padding: 0 0.25rem;
    border-radius: 0.25rem;
  }

  .tb-col-body {
    flex: 1;
    overflow-y: auto;
    padding: 0.375rem;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
  }

  .tb-card {
    background: var(--ctp-mantle);
    border: 1px solid var(--ctp-surface0);
    border-radius: 0.375rem;
    padding: 0.375rem 0.5rem;
    cursor: grab;
    transition: border-color 0.12s, opacity 0.12s;
  }

  .tb-card:hover { border-color: var(--ctp-surface1); }
  .tb-card.dragging { opacity: 0.4; }

  .card-header {
    display: flex;
    align-items: center;
    gap: 0.375rem;
  }

  .priority-dot {
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    flex-shrink: 0;
  }

  .card-title {
    flex: 1;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--ctp-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .card-delete {
    background: transparent;
    border: none;
    color: var(--ctp-overlay0);
    font-size: 0.875rem;
    cursor: pointer;
    padding: 0;
    line-height: 1;
    flex-shrink: 0;
    opacity: 0;
    transition: opacity 0.1s, color 0.1s;
  }

  .tb-card:hover .card-delete { opacity: 1; }
  .card-delete:hover { color: var(--ctp-red); }

  .card-desc {
    font-size: 0.6875rem;
    color: var(--ctp-subtext0);
    margin-top: 0.125rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .card-assignee {
    font-size: 0.625rem;
    color: var(--ctp-overlay1);
    margin-top: 0.25rem;
    display: flex;
    align-items: center;
    gap: 0.125rem;
  }

  .assignee-icon {
    color: var(--ctp-blue);
    font-weight: 700;
  }
</style>
