import type { Meta, StoryObj } from '@storybook/vue3-vite';
import { ref, computed, watch } from 'vue';
import { useFilter } from 'reka-ui';
import UiTagsInput from './UiTagsInput.vue';
import UiTagsInputInput from './UiTagsInputInput.vue';
import UiTagsInputItem from './UiTagsInputItem.vue';
import UiTagsInputItemText from './UiTagsInputItemText.vue';
import UiTagsInputItemDelete from './UiTagsInputItemDelete.vue';
import {
  UiPopover,
  UiPopoverTrigger,
  UiPopoverContent,
  UiPopoverAnchor,
} from '../UiPopover';
import { UiButton } from '../UiButton';
import {
  UiListbox,
  UiListboxContent,
  UiListboxFilter,
  UiListboxItem,
  UiListboxItemIndicator,
} from '../UiListbox';

/**
 * UiTagsInput is an input that collects multiple short string values as tags, with keyboard add/remove support.
 * Use it for free-form tags, recipient lists, and chip-style filters; pair with `UiPopover` + `UiListbox` for autocomplete suggestions.
 */
const meta: Meta<typeof UiTagsInput> = {
  title: 'Components/UiTagsInput',
  component: UiTagsInput,
  tags: ['autodocs'],
  argTypes: {
    disabled: {
      control: 'boolean',
      description: 'Disable the tags input',
    },
  },
  args: {
    disabled: false,
  },
};

export default meta;

type Story = StoryObj<typeof UiTagsInput>;

const defaultTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import {
  UiTagsInput,
  UiTagsInputInput,
  UiTagsInputItem,
  UiTagsInputItemText,
  UiTagsInputItemDelete
} from '@aleph-alpha/ui-library'

const modelValue = ref(['Apple', 'Banana'])
</script>

<template>
  <UiTagsInput v-model="modelValue" class="w-[300px]">
    <UiTagsInputItem v-for="item in modelValue" :key="item" :value="item">
      <UiTagsInputItemText />
      <UiTagsInputItemDelete />
    </UiTagsInputItem>

    <UiTagsInputInput placeholder="Fruits..." />
  </UiTagsInput>
</template>`;

/**
 * Default tags input with pre-filled values.
 */
export const Default: Story = {
  render: (args) => ({
    components: {
      UiTagsInput,
      UiTagsInputInput,
      UiTagsInputItem,
      UiTagsInputItemText,
      UiTagsInputItemDelete,
    },
    setup() {
      const modelValue = ref(['Apple', 'Banana']);
      return { args, modelValue };
    },
    template: `
      <UiTagsInput v-model="modelValue" class="w-[300px]" :disabled="args.disabled">
        <UiTagsInputItem v-for="item in modelValue" :key="item" :value="item">
          <UiTagsInputItemText />
          <UiTagsInputItemDelete />
        </UiTagsInputItem>

        <UiTagsInputInput placeholder="Fruits..." />
      </UiTagsInput>
    `,
  }),
  parameters: {
    docs: {
      source: {
        code: defaultTemplateSource,
      },
    },
  },
};

const emptyTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import {
  UiTagsInput,
  UiTagsInputInput,
  UiTagsInputItem,
  UiTagsInputItemText,
  UiTagsInputItemDelete
} from '@aleph-alpha/ui-library'

const modelValue = ref<string[]>([])
</script>

<template>
  <UiTagsInput v-model="modelValue" class="w-[300px]">
    <UiTagsInputItem v-for="item in modelValue" :key="item" :value="item">
      <UiTagsInputItemText />
      <UiTagsInputItemDelete />
    </UiTagsInputItem>

    <UiTagsInputInput placeholder="Add tags..." />
  </UiTagsInput>
</template>`;

/**
 * Empty tags input ready for user input.
 */
export const Empty: Story = {
  render: () => ({
    components: {
      UiTagsInput,
      UiTagsInputInput,
      UiTagsInputItem,
      UiTagsInputItemText,
      UiTagsInputItemDelete,
    },
    setup() {
      const modelValue = ref<string[]>([]);
      return { modelValue };
    },
    template: `
      <UiTagsInput v-model="modelValue" class="w-[300px]">
        <UiTagsInputItem v-for="item in modelValue" :key="item" :value="item">
          <UiTagsInputItemText />
          <UiTagsInputItemDelete />
        </UiTagsInputItem>

        <UiTagsInputInput placeholder="Add tags..." />
      </UiTagsInput>
    `,
  }),
  parameters: {
    docs: {
      source: {
        code: emptyTemplateSource,
      },
    },
  },
};

const disabledTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import {
  UiTagsInput,
  UiTagsInputInput,
  UiTagsInputItem,
  UiTagsInputItemText,
  UiTagsInputItemDelete
} from '@aleph-alpha/ui-library'

const modelValue = ref(['Vue', 'React', 'Angular'])
</script>

<template>
  <UiTagsInput v-model="modelValue" class="w-[300px]" disabled>
    <UiTagsInputItem v-for="item in modelValue" :key="item" :value="item">
      <UiTagsInputItemText />
      <UiTagsInputItemDelete />
    </UiTagsInputItem>

    <UiTagsInputInput placeholder="Add framework..." />
  </UiTagsInput>
</template>`;

/**
 * Disabled tags input.
 */
export const Disabled: Story = {
  args: {
    disabled: true,
  },
  render: () => ({
    components: {
      UiTagsInput,
      UiTagsInputInput,
      UiTagsInputItem,
      UiTagsInputItemText,
      UiTagsInputItemDelete,
    },
    setup() {
      const modelValue = ref(['Vue', 'React', 'Angular']);
      return { modelValue };
    },
    template: `
      <UiTagsInput v-model="modelValue" class="w-[300px] !opacity-100" disabled>
        <UiTagsInputItem v-for="item in modelValue" :key="item" :value="item">
          <UiTagsInputItemText />
          <UiTagsInputItemDelete />
        </UiTagsInputItem>

        <UiTagsInputInput placeholder="Add framework..." />
      </UiTagsInput>
    `,
  }),
  parameters: {
    a11y: {
      config: {
        rules: [{ id: 'color-contrast', enabled: false }],
      },
    },
    docs: {
      source: {
        code: disabledTemplateSource,
      },
    },
  },
};

const maxTagsTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import {
  UiTagsInput,
  UiTagsInputInput,
  UiTagsInputItem,
  UiTagsInputItemText,
  UiTagsInputItemDelete
} from '@aleph-alpha/ui-library'

const modelValue = ref(['Tag 1', 'Tag 2'])
</script>

<template>
  <UiTagsInput v-model="modelValue" class="w-[300px]" :max="3">
    <UiTagsInputItem v-for="item in modelValue" :key="item" :value="item">
      <UiTagsInputItemText />
      <UiTagsInputItemDelete />
    </UiTagsInputItem>

    <UiTagsInputInput placeholder="Max 3 tags..." />
  </UiTagsInput>
</template>`;

/**
 * Tags input with a maximum number of tags (3).
 */
export const MaxTags: Story = {
  render: () => ({
    components: {
      UiTagsInput,
      UiTagsInputInput,
      UiTagsInputItem,
      UiTagsInputItemText,
      UiTagsInputItemDelete,
    },
    setup() {
      const modelValue = ref(['Tag 1', 'Tag 2']);
      return { modelValue };
    },
    template: `
      <UiTagsInput v-model="modelValue" class="w-[300px]" :max="3">
        <UiTagsInputItem v-for="item in modelValue" :key="item" :value="item">
          <UiTagsInputItemText />
          <UiTagsInputItemDelete />
        </UiTagsInputItem>

        <UiTagsInputInput placeholder="Max 3 tags..." />
      </UiTagsInput>
    `,
  }),
  parameters: {
    docs: {
      source: {
        code: maxTagsTemplateSource,
      },
    },
  },
};

const emailsTemplateSource = `<script setup lang="ts">
import { ref } from 'vue'
import {
  UiTagsInput,
  UiTagsInputInput,
  UiTagsInputItem,
  UiTagsInputItemText,
  UiTagsInputItemDelete
} from '@aleph-alpha/ui-library'

const emails = ref(['john@example.com', 'jane@example.com'])
</script>

<template>
  <UiTagsInput v-model="emails" class="w-[400px]">
    <UiTagsInputItem v-for="email in emails" :key="email" :value="email">
      <UiTagsInputItemText />
      <UiTagsInputItemDelete />
    </UiTagsInputItem>

    <UiTagsInputInput placeholder="Add email address..." />
  </UiTagsInput>
</template>`;

/**
 * Tags input for email addresses.
 */
export const EmailInput: Story = {
  render: () => ({
    components: {
      UiTagsInput,
      UiTagsInputInput,
      UiTagsInputItem,
      UiTagsInputItemText,
      UiTagsInputItemDelete,
    },
    setup() {
      const emails = ref(['john@example.com', 'jane@example.com']);
      return { emails };
    },
    template: `
      <UiTagsInput v-model="emails" class="w-[400px]">
        <UiTagsInputItem v-for="email in emails" :key="email" :value="email">
          <UiTagsInputItemText />
          <UiTagsInputItemDelete />
        </UiTagsInputItem>

        <UiTagsInputInput placeholder="Add email address..." />
      </UiTagsInput>
    `,
  }),
  parameters: {
    docs: {
      source: {
        code: emailsTemplateSource,
      },
    },
  },
};

const withListboxTemplateSource = `<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { useFilter } from 'reka-ui'
import {
  UiTagsInput,
  UiTagsInputInput,
  UiTagsInputItem,
  UiTagsInputItemText,
  UiTagsInputItemDelete,
  UiPopover,
  UiPopoverTrigger,
  UiPopoverContent,
  UiPopoverAnchor,
  UiButton,
  UiListbox,
  UiListboxContent,
  UiListboxFilter,
  UiListboxItem,
  UiListboxItemIndicator
} from '@aleph-alpha/ui-library'

const frameworks = [
  { value: 'next.js', label: 'Next.js' },
  { value: 'sveltekit', label: 'SvelteKit' },
  { value: 'nuxt', label: 'Nuxt' },
  { value: 'remix', label: 'Remix' },
  { value: 'astro', label: 'Astro' },
]

const searchTerm = ref('')
const selectedFrameworks = ref(['Nuxt', 'Remix'])
const open = ref(false)

const { contains } = useFilter({ sensitivity: 'base' })

const filteredFrameworks = computed(() =>
  searchTerm.value === ''
    ? frameworks
    : frameworks.filter(option => contains(option.label, searchTerm.value))
)

watch(searchTerm, (value) => {
  if (value) {
    open.value = true
  }
})
</script>

<template>
  <UiPopover v-model:open="open">
    <UiListbox
      v-model="selectedFrameworks"
      highlight-on-hover
      multiple
      class="rounded-none border-0 bg-transparent shadow-none"
    >
      <UiPopoverAnchor class="inline-flex w-[300px]">
        <UiTagsInput v-slot="{ modelValue: tags }" v-model="selectedFrameworks" class="w-full">
          <UiTagsInputItem v-for="item in tags" :key="item.toString()" :value="item.toString()">
            <UiTagsInputItemText />
            <UiTagsInputItemDelete />
          </UiTagsInputItem>

          <UiListboxFilter v-model="searchTerm" as-child>
            <UiTagsInputInput placeholder="Frameworks..." @keydown.enter.prevent @keydown.down="open = true" />
          </UiListboxFilter>

          <UiPopoverTrigger as-child>
            <UiButton size="icon-sm" variant="ghost" class="order-last self-start ml-auto">
              <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <path d="m6 9 6 6 6-6"/>
              </svg>
            </UiButton>
          </UiPopoverTrigger>
        </UiTagsInput>
      </UiPopoverAnchor>

      <UiPopoverContent class="p-1" @open-auto-focus.prevent>
        <UiListboxContent tabindex="0">
          <UiListboxItem
            v-for="item in filteredFrameworks"
            :key="item.value"
            :value="item.label"
            @select="searchTerm = ''"
          >
            <span>{{ item.label }}</span>
            <UiListboxItemIndicator />
          </UiListboxItem>
        </UiListboxContent>
      </UiPopoverContent>
    </UiListbox>
  </UiPopover>
</template>`;

/**
 * Tags input combined with a listbox in a popover for selecting from predefined options.
 * This pattern allows users to either type custom tags or select from a dropdown.
 */
export const WithListbox: Story = {
  render: () => ({
    components: {
      UiTagsInput,
      UiTagsInputInput,
      UiTagsInputItem,
      UiTagsInputItemText,
      UiTagsInputItemDelete,
      UiPopover,
      UiPopoverTrigger,
      UiPopoverContent,
      UiPopoverAnchor,
      UiButton,
      UiListbox,
      UiListboxContent,
      UiListboxFilter,
      UiListboxItem,
      UiListboxItemIndicator,
    },
    setup() {
      const frameworks = [
        { value: 'next.js', label: 'Next.js' },
        { value: 'sveltekit', label: 'SvelteKit' },
        { value: 'nuxt', label: 'Nuxt' },
        { value: 'remix', label: 'Remix' },
        { value: 'astro', label: 'Astro' },
      ];

      const searchTerm = ref('');
      const selectedFrameworks = ref(['Nuxt', 'Remix']);
      const open = ref(false);

      const { contains } = useFilter({ sensitivity: 'base' });

      const filteredFrameworks = computed(() =>
        searchTerm.value === ''
          ? frameworks
          : frameworks.filter((option) =>
              contains(option.label, searchTerm.value),
            ),
      );

      watch(searchTerm, (value) => {
        if (value) {
          open.value = true;
        }
      });

      return {
        frameworks,
        searchTerm,
        selectedFrameworks,
        open,
        filteredFrameworks,
      };
    },
    template: `
      <UiPopover v-model:open="open">
        <UiListbox
          v-model="selectedFrameworks"
          highlight-on-hover
          multiple
          class="rounded-none border-0 bg-transparent shadow-none"
        >
          <UiPopoverAnchor class="inline-flex w-[300px]">
            <UiTagsInput v-slot="{ modelValue: tags }" v-model="selectedFrameworks" class="w-full">
              <UiTagsInputItem v-for="item in tags" :key="item.toString()" :value="item.toString()">
                <UiTagsInputItemText />
                <UiTagsInputItemDelete />
              </UiTagsInputItem>

              <UiListboxFilter v-model="searchTerm" as-child>
                <UiTagsInputInput placeholder="Frameworks..." @keydown.enter.prevent @keydown.down="open = true" />
              </UiListboxFilter>

              <UiPopoverTrigger as-child>
                <UiButton
                  size="icon-sm"
                  variant="ghost"
                  class="order-last self-start ml-auto"
                  aria-label="Open framework suggestions"
                >
                  <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <path d="m6 9 6 6 6-6"/>
                  </svg>
                </UiButton>
              </UiPopoverTrigger>
            </UiTagsInput>
          </UiPopoverAnchor>

          <UiPopoverContent class="p-1" @open-auto-focus.prevent>
            <UiListboxContent tabindex="0">
              <UiListboxItem
                v-for="item in filteredFrameworks"
                :key="item.value"
                :value="item.label"
                @select="searchTerm = ''"
              >
                <span>{{ item.label }}</span>
                <UiListboxItemIndicator />
              </UiListboxItem>
            </UiListboxContent>
          </UiPopoverContent>
        </UiListbox>
      </UiPopover>
    `,
  }),
  parameters: {
    docs: {
      source: {
        code: withListboxTemplateSource,
      },
    },
  },
};
