import type { Meta, StoryObj } from '@storybook/react-vite'
import { expect, userEvent, screen } from 'storybook/test'
import { useState } from 'react'
import {
  Select,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectLabel,
  SelectSeparator,
  SelectTrigger,
  SelectValue,
} from './select'

const meta = {
  title: 'Select',
  component: Select,
  parameters: {
    layout: 'centered',
  },
  tags: ['autodocs'],
  argTypes: {
    disabled: {
      control: 'boolean',
    },
    selectTriggerSize: {
      control: 'select',
      options: ['default', 'xs', 'sm', 'lg'],
    },
    selectTriggerStyle: {
      control: 'select',
      options: ['default', 'simple'],
    },
    selectItemType: {
      control: 'select',
      options: ['default', 'deselect'],
    },
    selectItemSpacing: {
      control: 'select',
      options: ['sm', 'md', 'lg'],
    },
  },
  args: {
    disabled: false,
    selectTriggerSize: 'default',
    selectTriggerStyle: 'default',
    selectItemType: 'default',
    selectItemSpacing: 'md',
  },
}
export default meta

interface SelectStoryArgs {
  disabled?: boolean
  selectTriggerSize?: 'default' | 'xs' | 'sm' | 'lg'
  selectTriggerStyle?: 'default' | 'simple'
  selectItemType?: 'default' | 'deselect'
  selectItemSpacing?: 'sm' | 'md' | 'lg'
}

type Story = StoryObj<SelectStoryArgs>

const options = [
  { value: 'apple', label: 'Apple' },
  { value: 'banana', label: 'Banana' },
  { value: 'orange', label: 'Orange' },
  { value: 'grape', label: 'Grape' },
  { value: 'watermelon', label: 'Watermelon' },
]

export const Default: Story = {
  render: (args) => (
    <Select {...args}>
      <SelectTrigger
        className="w-[200px]"
        data-testid="select-trigger"
        size={args.selectTriggerSize}
        variant={args.selectTriggerStyle}
      >
        <SelectValue placeholder="Select a fruit" />
      </SelectTrigger>
      <SelectContent>
        {options.map((option) => (
          <SelectItem
            key={option.value}
            value={option.value}
            spacing={args.selectItemSpacing}
            type={args.selectItemType}
          >
            {option.label}
          </SelectItem>
        ))}
      </SelectContent>
    </Select>
  ),
  play: async () => {
    const selectTrigger = screen.getByTestId('select-trigger')

    await userEvent.click(selectTrigger)
    // Wait for dropdown to appear
    await new Promise((resolve) => setTimeout(resolve, 100))

    // Check if dropdown content is visible
    const dropdown = document.querySelector('[role="listbox"]')
    await expect(dropdown).toBeInTheDocument()
  },
}

export const TriggerStyles: Story = {
  render: () => (
    <div className="flex flex-wrap gap-2 items-center">
      {meta.argTypes.selectTriggerStyle.options.map((style) => (
        <Select key={style}>
          <SelectTrigger className="w-[200px]" variant={style as SelectStoryArgs['selectTriggerStyle']}>
            <SelectValue placeholder={style.charAt(0).toUpperCase() + style.slice(1)} />
          </SelectTrigger>
          <SelectContent>
            {options.map((option) => (
              <SelectItem key={option.value} value={option.value}>
                {option.label}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      ))}
    </div>
  ),
}

export const TriggerSizes: Story = {
  render: () => (
    <div className="flex flex-wrap gap-2 items-center">
      {meta.argTypes.selectTriggerSize.options.map((size) => (
        <Select key={size}>
          <SelectTrigger className="w-[200px]" size={size as SelectStoryArgs['selectTriggerSize']}>
            <SelectValue placeholder={size} />
          </SelectTrigger>
          <SelectContent>
            {options.map((option) => (
              <SelectItem key={option.value} value={option.value}>
                {option.label}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      ))}
    </div>
  ),
}

export const ItemSpacings: Story = {
  render: () => (
    <div className="flex flex-wrap gap-2 items-center">
      {meta.argTypes.selectItemSpacing.options.map((spacing) => (
        <Select key={spacing}>
          <SelectTrigger className="w-[200px]">
            <SelectValue placeholder={spacing} />
          </SelectTrigger>
          <SelectContent>
            {options.map((option) => (
              <SelectItem
                key={option.value}
                value={option.value}
                spacing={spacing as SelectStoryArgs['selectItemSpacing']}
              >
                {option.label}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      ))}
    </div>
  ),
}

export const WithDeselectOption: Story = {
  render: () => {
    const [selected, setSelected] = useState<string | null>(null)
    return (
      <Select value={selected ?? ''} onValueChange={(val) => setSelected(val === 'deselect' ? null : val)}>
        <SelectTrigger data-testid="select-trigger" className="w-[200px]">
          <SelectValue placeholder="Select a fruit" />
        </SelectTrigger>
        <SelectContent>
          <SelectItem type="deselect" value="deselect">
            None
          </SelectItem>
          {options.map((option) => (
            <SelectItem key={option.value} value={option.value}>
              {option.label}
            </SelectItem>
          ))}
        </SelectContent>
      </Select>
    )
  },
  play: async () => {
    const selectTrigger = screen.getByTestId('select-trigger')
    expect(selectTrigger).toHaveTextContent('Select a fruit')
    // Open select
    await userEvent.click(selectTrigger)
    // Select "Banana"
    const bananaOption = screen.getByText('Banana')
    await userEvent.click(bananaOption)
    expect(selectTrigger).toHaveTextContent('Banana')
    // Open dropdown and select "None" (deselect)
    await userEvent.click(selectTrigger)
    const noneOption = screen.getByText('None')
    await userEvent.click(noneOption)
    expect(selectTrigger).toHaveTextContent('Select a fruit')
  },
}

export const Disabled: Story = {
  render: () => (
    <Select disabled>
      <SelectTrigger className="w-[200px]" data-testid="disabled-select">
        <SelectValue placeholder="Select a fruit" />
      </SelectTrigger>
      <SelectContent>
        {options.map((option) => (
          <SelectItem key={option.value} value={option.value}>
            {option.label}
          </SelectItem>
        ))}
      </SelectContent>
    </Select>
  ),
}

export const WithGroupsDefaultAndDisabledOption: Story = {
  render: () => (
    <Select defaultValue="banana">
      <SelectTrigger className="w-[200px]">
        <SelectValue placeholder="Select a fruit" />
      </SelectTrigger>
      <SelectContent>
        <SelectGroup>
          <SelectLabel>Citrus Group</SelectLabel>
          <SelectItem value="orange">Orange</SelectItem>
          <SelectItem value="lemon">Lemon</SelectItem>
          <SelectItem value="lime" disabled>
            Lime (Unavailable)
          </SelectItem>
        </SelectGroup>
        <SelectSeparator />
        <SelectItem value="banana">Banana (Default)</SelectItem>
        <SelectItem value="watermelon">Watermelon</SelectItem>
      </SelectContent>
    </Select>
  ),
  name: 'With Groups, Default and Disabled Option',
}

export const InteractiveTest: Story = {
  render: () => (
    <Select>
      <SelectTrigger className="w-[200px]" data-testid="select-trigger">
        <SelectValue placeholder="Select a fruit" data-testid="select-value" />
      </SelectTrigger>
      <SelectContent>
        {options.map((option) => (
          <SelectItem key={option.value} value={option.value} data-testid={`option-${option.value}`}>
            {option.label}
          </SelectItem>
        ))}
      </SelectContent>
    </Select>
  ),
  play: async () => {
    const selectTrigger = screen.getByTestId('select-trigger')
    expect(selectTrigger).toHaveTextContent('Select a fruit')
    await userEvent.click(selectTrigger)

    await new Promise((resolve) => setTimeout(resolve, 100))

    const dropdown = document.querySelector('[role="listbox"]')
    expect(dropdown).toBeInTheDocument()

    const bananaOption = screen.getByText('Banana')
    await userEvent.click(bananaOption)

    await new Promise((resolve) => setTimeout(resolve, 100))

    expect(selectTrigger).toHaveTextContent('Banana')

    await userEvent.click(selectTrigger)
    await new Promise((resolve) => setTimeout(resolve, 100))

    const grapeOption = screen.getByText('Grape')
    await userEvent.click(grapeOption)

    await new Promise((resolve) => setTimeout(resolve, 100))

    expect(selectTrigger).toHaveTextContent('Grape')
  },
}
