import type { StoryObj } from '@storybook/react-vite'

import {
  Command,
  CommandEmpty,
  CommandInput,
  CommandItem,
  CommandList,
  CommandGroup,
  CommandSeparator,
  CommandShortcut,
  CommandInputProps,
} from './command'
import { expect, userEvent, waitFor, screen } from 'storybook/test'
import { useState } from 'storybook/preview-api'

const CommandWithInput = ({
  variant: inputVariant,
  inputSize,
  showContent = true,
  searchValue,
  setSearchValue,
  placeholder,
  ...rest
}: CommandProps & { showContent?: boolean } & { searchValue?: string } & {
  setSearchValue?: (val: string) => void
}) => (
  <Command {...rest} className="w-[250px] border">
    <CommandInput
      placeholder={placeholder}
      variant={inputVariant}
      inputSize={inputSize}
      value={searchValue}
      onValueChange={(val) => {
        setSearchValue?.(val)
      }}
    />
    {showContent && (
      <CommandList>
        <CommandEmpty>No results found.</CommandEmpty>
        <CommandGroup heading="Category 1">
          <CommandItem>
            <span>Item</span>
          </CommandItem>
          <CommandItem disabled>
            <span>Disabled item</span>
          </CommandItem>
        </CommandGroup>
        <CommandSeparator />
        <CommandGroup heading="Category 2">
          <CommandItem>
            <span>With shortcut</span>
            <CommandShortcut>⌘P (only visually)</CommandShortcut>
          </CommandItem>
        </CommandGroup>
      </CommandList>
    )}
  </Command>
)

const meta = {
  title: 'Command',
  component: CommandWithInput,
  tags: ['autodocs'],
  parameters: {
    layout: 'centered',
  },
  argTypes: {
    inputVariant: {
      control: 'select',
      options: ['default', 'borderless'],
    },
    inputSize: {
      control: 'select',
      options: ['md', 'sm', 'lg'],
    },
  },
}
export default meta

interface CommandStoryArgs {
  inputVariant?: 'default' | 'borderless'
  inputSize?: 'md' | 'sm' | 'lg'
}

type Story = StoryObj<CommandStoryArgs>

type CommandProps = CommandInputProps &
  React.ComponentProps<typeof Command> & {
    inputVariant?: 'default' | 'borderless'
  }

export const Default: Story = {
  render: (args) => (
    <CommandWithInput
      variant={args.inputVariant}
      inputSize={args.inputSize}
      placeholder="Command with border and w-[250px]"
    />
  ),
}

export const InputVariants: Story = {
  render: () => (
    <div className="flex flex-wrap gap-4">
      <CommandWithInput variant="default" inputSize="md" placeholder="Command with border and w-[250px]" />
      <CommandWithInput variant="borderless" inputSize="md" placeholder="Command with border and w-[250px]" />
    </div>
  ),
}

export const InputSizes: Story = {
  render: () => (
    <div className="flex flex-wrap gap-4 items-center">
      <CommandWithInput
        variant="borderless"
        inputSize="sm"
        showContent={false}
        placeholder="Command with border and w-[250px]"
      />
      <CommandWithInput
        variant="borderless"
        inputSize="md"
        showContent={false}
        placeholder="Command with border and w-[250px]"
      />
      <CommandWithInput
        variant="borderless"
        inputSize="lg"
        showContent={false}
        placeholder="Command with border and w-[250px]"
      />
    </div>
  ),
}

export const InteractiveExample: Story = {
  render: () => {
    const [open, setOpen] = useState(false)
    const [searchValue, setSearchValue] = useState('')
    return (
      <CommandWithInput
        variant={open ? 'default' : 'borderless'}
        inputSize="md"
        placeholder="Type a command or search..."
        searchValue={searchValue}
        setSearchValue={(val) => {
          setSearchValue(val)
        }}
        showContent={open}
        onBlur={() => {
          setOpen(false)
          setSearchValue('')
        }}
        onFocus={() => setOpen(true)}
      />
    )
  },
  play: async () => {
    const input = screen.getByPlaceholderText('Type a command or search...')

    // 1. Dropdown should be closed initially
    await expect(screen.queryByText('Category 1')).toBeNull()
    // 2. Focus input, dropdown opens
    await userEvent.click(input)
    // await expect(await screen.findByText('Category 1')).toBeVisible()
    // 3. Type to filter items
    await userEvent.type(input, 'Item')
    // await expect(await screen.findByText('Item')).toBeVisible()
    await expect(screen.queryByText('With shortcut')).toBeNull()
    // 4. Clear input, all items visible again
    await userEvent.clear(input)
    // await expect(await screen.findByText('Category 1')).toBeVisible()
    // await expect(await screen.findByText('With shortcut')).toBeVisible()
    // 5. Blur input, dropdown closes
    await userEvent.tab()
    await waitFor(() => {
      const el = screen.queryByText('Category 1')
      expect(!el || el.getAttribute('aria-hidden') === 'true').toBe(true)
    })
    // 6. check that value is reset correctly
    const inputField = screen.getByPlaceholderText('Type a command or search...')
    await expect(inputField).toHaveValue('')
    await expect(inputField).not.toHaveFocus()
  },
}
