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

import { MarkValueRenderer } from './mark-value-renderer'
import { useRef, useState } from 'react'
import { expect, userEvent, screen, within } from 'storybook/test'
import { Command, CommandEmpty, CommandInput, CommandItem, CommandList } from '@components/ui/command/command'

const meta = {
  title: 'MarkValueRenderer',
  component: MarkValueRenderer,
  tags: ['autodocs'],
  parameters: {
    layout: 'centered',
  },
} satisfies Meta<typeof MarkValueRenderer>
export default meta

type Story = StoryObj<typeof meta>

export const Default: Story = {
  args: {
    text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus porttitor nisl velit, at posuere nisi mollis rutrum. Mauris rutrum blandit metus, non rutrum ante luctus non. Donec magna metus, congue vel sodales ut, auctor a metus.',
    searchValues: ['Phasellus port', 'etu', 'NotFound'],
  },
  render: (args) => (
    <div className="">
      <MarkValueRenderer {...args} />
    </div>
  ),
}

export const InteractiveExample: Story = {
  args: { text: '', searchValues: [] },
  render: () => {
    const [open, setOpen] = useState(false)
    const [searchValue, setSearchValue] = useState('')
    const allValues = [
      'Black leather laptop bag',
      'Laptop backpack with USB charging port',
      'Stainless steel reusable water bottle',
      'Glass water bottle with silicone sleeve',
      'Wireless Bluetooth headphones with noise cancellation',
      'Over-ear headphones with built-in microphone',
      'Ergonomic keyboard with backlight',
      'Compact Bluetooth keyboard for tablet and phone',
      'Digital camera with interchangeable lens',
      'Compact travel camera with 4K resolution',
      'Men`s wristwatch with stainless steel case',
      'Smartwatch with heart rate monitor and GPS',
      'Classic umbrella with wooden handle',
      'Automatic folding umbrella in black',
      'Recycled paper notebook with leather cover',
    ]
    const [selectedValue, setSelectedValue] = useState<string>('')
    const commandRef = useRef<HTMLDivElement>(null)

    return (
      <div ref={commandRef}>
        <Command
          className="w-[350px] border"
          onFocus={() => setOpen(true)}
          onBlur={(e) => {
            if (commandRef.current && !commandRef.current.contains(e.relatedTarget as Node)) {
              setOpen(false)
              setSearchValue('')
            }
          }}
        >
          <CommandInput
            placeholder={selectedValue || 'Search...'}
            variant={open ? 'default' : 'borderless'}
            inputSize="md"
            value={searchValue}
            onValueChange={(val) => {
              setSearchValue(val)
            }}
          />
          {open && (
            <CommandList>
              <CommandEmpty data-testid="no-results">No results found.</CommandEmpty>
              {allValues.map((value) => (
                <CommandItem
                  key={value}
                  data-testid={`item-${value}`}
                  onSelect={() => {
                    setSelectedValue(value)
                    setOpen(false)
                    setSearchValue('')
                  }}
                >
                  {searchValue ? <MarkValueRenderer text={value} searchValues={[searchValue]} /> : value}
                </CommandItem>
              ))}
            </CommandList>
          )}
        </Command>
      </div>
    )
  },
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement)
    const commandInput = canvas.getByPlaceholderText('Search...')
    await userEvent.click(commandInput)
    await userEvent.type(commandInput, 'leather')

    const item = await canvas.findByTestId('item-Recycled paper notebook with leather cover')
    // the MarkValueRenderer wraps matches in <mark>, so find that fragment directly
    const highlighted = item.querySelector('mark')
    if (!highlighted) throw new Error('Highlighted fragment (<mark>) not found inside the item')
    const highlightedColor = window.getComputedStyle(highlighted).color
    const itemColor = window.getComputedStyle(item).color
    expect(highlightedColor).not.toBe(itemColor)
  },
}
