import type { Meta, StoryObj } from '@storybook/vue3-vite';
import { ref } from 'vue';
import { useDrag } from './useDrag';

type StoryItem = {
  id: string;
  label: string;
};

type CardItem = StoryItem & {
  description: string;
};

const initialItems: StoryItem[] = [
  { id: 'status', label: 'Status' },
  { id: 'email', label: 'Email' },
  { id: 'amount', label: 'Amount' },
  { id: 'actions', label: 'Actions' },
];

const initialCards: CardItem[] = [
  {
    id: 'research',
    label: 'Research',
    description: 'Collect requirements and compare implementation options.',
  },
  {
    id: 'design',
    label: 'Design',
    description: 'Shape the interaction model and visual treatment.',
  },
  {
    id: 'build',
    label: 'Build',
    description: 'Implement the selected approach and wire state.',
  },
  {
    id: 'verify',
    label: 'Verify',
    description: 'Run tests and review the behavior in Storybook.',
  },
];

const meta = {
  title: 'Utilities/useDrag',
  tags: ['autodocs'],
  parameters: {
    docs: {
      description: {
        component:
          '`useDrag()` groups native drag-and-drop helpers for sortable UI patterns: drag data, empty drag ghosts, cleanup, and immutable item reordering.',
      },
    },
  },
} satisfies Meta;

export default meta;
type Story = StoryObj<typeof meta>;

function setupCardDragStory() {
  const items = ref([...initialCards]);
  const {
    activeItemId,
    draggedItemId,
    dragOver,
    onDrop,
    resetDragState,
    startDrag,
  } = useDrag({ items, getItemId: (item) => item.id });

  function onDragStart(event: DragEvent, itemId: string) {
    const rect = (event.currentTarget as HTMLElement).getBoundingClientRect();
    startDrag(event, itemId, {
      width: rect.width,
      height: rect.height,
      className: 'rounded-lg border-2 border-border-surface-focus-ring',
    });
  }

  return {
    activeItemId,
    draggedItemId,
    dragOver,
    items,
    onDragStart,
    onDrop,
    resetDragState,
  };
}

export const UseDrag: Story = {
  parameters: {
    docs: {
      source: {
        code: `<script setup lang="ts">
import { ref } from 'vue';
import { useDrag } from '@aleph-alpha/ui-library';

const items = ref([
  { id: 'status', label: 'Status' },
  { id: 'email', label: 'Email' },
  { id: 'amount', label: 'Amount' },
  { id: 'actions', label: 'Actions' },
]);

const {
  activeItem,
  activeItemId,
  draggedItem,
  draggedItemId,
  dragOver,
  onDrop,
  originalItems,
  resetDragState,
  startDrag,
} = useDrag({ items, getItemId: (item) => item.id });

function onDragStart(event: DragEvent, itemId: string) {
  startDrag(event, itemId, {
    width: 180,
    height: 44,
    className: 'rounded-md border-2 border-border-surface-focus-ring',
  });
}
</script>

<template>
  <div class="max-w-md space-y-3">
    <p class="text-muted-foreground text-sm">
      Drag an item over another item. The helper keeps the native drag data,
      creates an empty bordered ghost, and reorders on drop.
    </p>
    <div class="space-y-2">
      <div
        v-for="item in items"
        :key="item.id"
        draggable="true"
        :class="[
          'rounded-md border border-border-surface-default bg-background-surface-primary px-3 py-2 text-sm transition-[border-color,opacity,transform]',
          draggedItemId === item.id ? 'opacity-50' : undefined,
          activeItemId === item.id ? 'border-border-surface-focus-ring' : undefined,
        ]"
        @dragstart="onDragStart($event, item.id)"
        @dragover="dragOver($event, item.id)"
        @drop="onDrop($event, item.id)"
        @dragend="resetDragState"
      >
        {{ item.label }}
      </div>
    </div>
    <div class="text-muted-foreground grid gap-1 text-xs">
      <span>Dragged item: {{ draggedItem?.label ?? 'none' }}</span>
      <span>Active item: {{ activeItem?.label ?? 'none' }}</span>
      <span>Original order: {{ originalItems?.map((item) => item.id).join(' -> ') ?? 'none' }}</span>
    </div>
    <pre class="rounded-md bg-background-surface-muted p-3 text-xs">{{ items.map((item) => item.id).join(' -> ') }}</pre>
  </div>
</template>`,
      },
    },
  },
  render: () => ({
    setup() {
      const items = ref([...initialItems]);
      const {
        activeItem,
        activeItemId,
        draggedItem,
        draggedItemId,
        dragOver,
        onDrop,
        originalItems,
        resetDragState,
        startDrag,
      } = useDrag({ items, getItemId: (item) => item.id });

      function onDragStart(event: DragEvent, itemId: string) {
        startDrag(event, itemId, {
          width: 180,
          height: 44,
          className: 'rounded-md border-2 border-border-surface-focus-ring',
        });
      }

      return {
        items,
        activeItem,
        draggedItemId,
        draggedItem,
        activeItemId,
        dragOver,
        onDragStart,
        onDrop,
        originalItems,
        resetDragState,
      };
    },
    template: `
      <div class="max-w-md space-y-3">
        <p class="text-muted-foreground text-sm">
          Drag an item over another item. The helper keeps the native drag data,
          creates an empty bordered ghost, and reorders on drop.
        </p>
        <div class="space-y-2">
          <div
            v-for="item in items"
            :key="item.id"
            draggable="true"
            :class="[
              'rounded-md border border-border-surface-default bg-background-surface-primary px-3 py-2 text-sm transition-[border-color,opacity,transform]',
              draggedItemId === item.id ? 'opacity-50' : undefined,
              activeItemId === item.id ? 'border-border-surface-focus-ring' : undefined,
            ]"
            @dragstart="onDragStart($event, item.id)"
            @dragover="dragOver($event, item.id)"
            @drop="onDrop($event, item.id)"
            @dragend="resetDragState"
          >
            {{ item.label }}
          </div>
        </div>
        <div class="text-muted-foreground grid gap-1 text-xs">
          <span>Dragged item: {{ draggedItem?.label ?? 'none' }}</span>
          <span>Active item: {{ activeItem?.label ?? 'none' }}</span>
          <span>Original order: {{ originalItems?.map((item) => item.id).join(' -> ') ?? 'none' }}</span>
        </div>
        <pre class="rounded-md bg-background-surface-muted p-3 text-xs">{{ items.map((item) => item.id).join(' -> ') }}</pre>
      </div>
    `,
  }),
};

export const VerticalCards: Story = {
  render: () => ({
    setup: setupCardDragStory,
    template: `
      <div class="max-w-lg space-y-3">
        <p class="text-muted-foreground text-sm">
          Vertical card sorting with model-backed drop handling.
        </p>
        <div class="space-y-3">
          <article
            v-for="item in items"
            :key="item.id"
            draggable="true"
            :class="[
              'cursor-grab rounded-lg border border-border-surface-default bg-background-surface-primary p-4 shadow-xs transition-[border-color,opacity,transform] active:cursor-grabbing',
              draggedItemId === item.id ? 'opacity-50' : undefined,
              activeItemId === item.id ? 'border-border-surface-focus-ring' : undefined,
            ]"
            @dragstart="onDragStart($event, item.id)"
            @dragover="dragOver($event, item.id)"
            @drop="onDrop($event, item.id)"
            @dragend="resetDragState"
          >
            <h3 class="label-14-medium text-content-on-surface-primary">{{ item.label }}</h3>
            <p class="text-muted-foreground mt-1 text-sm">{{ item.description }}</p>
          </article>
        </div>
      </div>
    `,
  }),
};

export const GridCards: Story = {
  render: () => ({
    setup: setupCardDragStory,
    template: `
      <div class="max-w-3xl space-y-3">
        <p class="text-muted-foreground text-sm">
          Grid card sorting uses the same active-item model and default drop reorder.
        </p>
        <div class="grid gap-3 sm:grid-cols-2">
          <article
            v-for="item in items"
            :key="item.id"
            draggable="true"
            :class="[
              'min-h-32 cursor-grab rounded-lg border border-border-surface-default bg-background-surface-primary p-4 shadow-xs transition-[border-color,opacity,transform] active:cursor-grabbing',
              draggedItemId === item.id ? 'opacity-50' : undefined,
              activeItemId === item.id ? 'border-border-surface-focus-ring' : undefined,
            ]"
            @dragstart="onDragStart($event, item.id)"
            @dragover="dragOver($event, item.id)"
            @drop="onDrop($event, item.id)"
            @dragend="resetDragState"
          >
            <h3 class="label-14-medium text-content-on-surface-primary">{{ item.label }}</h3>
            <p class="text-muted-foreground mt-2 text-sm">{{ item.description }}</p>
          </article>
        </div>
      </div>
    `,
  }),
};
