import type { Meta, StoryObj } from '@storybook/react'
import type React from 'react'
import { expect, userEvent, waitFor } from 'storybook/test'
import { SvgCog } from '@chainlink/blocks-icons'
import { cn } from '../../utils'
import { viewports } from '../../utils/viewports'
import { Button, ButtonIcon } from '../Button'
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from '../DropdownMenu'
import {
  LegacyCombobox,
  LegacyComboboxContent,
  LegacyComboboxTrigger,
  LegacyComboboxValue,
  OptionRow,
} from '../LegacyCombobox'
import { MultiSelect } from '../MultiSelect/MultiSelect'
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '../Select'
import {
  SidePanel,
  SidePanelTrigger,
  SidePanelScrollArea,
  SidePanelContent,
  SidePanelTitle,
  SidePanelFooter,
  SidePanelHeader,
  SidePanelCloseMobile,
} from './SidePanel'

export default {
  title: 'Blocks/SidePanel',
  component: SidePanel,
  parameters: {
    chromatic: { viewports: viewports.all },
  },
} satisfies Meta<typeof SidePanel>

type Story = StoryObj<typeof SidePanel>

const PlaceholderContent: React.FC = () => (
  <div className="grid gap-2 p-6">
    {new Array(55).fill(0).map((_workflowId, i) => (
      <div
        className={cn(
          'h-4 animate-pulse bg-background-alt odd:w-96 odd:bg-brand even:w-80 even:bg-brand/50',
        )}
        style={{ animationDelay: `${i * 0.1}s` }}
        key={i}
      ></div>
    ))}
  </div>
)

export const Default: Story = {
  render: (_args, context) => (
    <SidePanel defaultOpen={context.viewMode === 'story'}>
      <SidePanelTrigger asChild>
        <Button>SidePanel Without Footer</Button>
      </SidePanelTrigger>
      <SidePanelContent>
        <SidePanelHeader>
          <SidePanelTitle>Workflow Arigato Sama</SidePanelTitle>
        </SidePanelHeader>
        <SidePanelScrollArea>
          <PlaceholderContent />
        </SidePanelScrollArea>
      </SidePanelContent>
    </SidePanel>
  ),
}

export const WithFooter: Story = {
  render: (_args, context) => (
    <SidePanel defaultOpen={context.viewMode === 'story'}>
      <SidePanelTrigger asChild>
        <Button>Open SidePanel</Button>
      </SidePanelTrigger>
      <SidePanelContent variant="narrow">
        <SidePanelHeader>
          <SidePanelTitle>Workflow Arigato Sama</SidePanelTitle>
        </SidePanelHeader>
        <SidePanelScrollArea>
          <PlaceholderContent />
        </SidePanelScrollArea>
        <SidePanelFooter>Footer actions</SidePanelFooter>
      </SidePanelContent>
    </SidePanel>
  ),
}

export const WideVariant: Story = {
  render: (_args, context) => (
    <SidePanel defaultOpen={context.viewMode === 'story'}>
      <SidePanelTrigger asChild>
        <Button>Open Wide SidePanel</Button>
      </SidePanelTrigger>
      <SidePanelContent variant="wide">
        <SidePanelHeader>
          <SidePanelTitle>Wide Workflow Arigato Sama</SidePanelTitle>
        </SidePanelHeader>
        <SidePanelScrollArea>
          <PlaceholderContent />
        </SidePanelScrollArea>
        <SidePanelFooter>Footer actions</SidePanelFooter>
      </SidePanelContent>
    </SidePanel>
  ),
}

export const WithAdditionalRightSideButton: Story = {
  render: (_args, context) => (
    <SidePanel defaultOpen={context.viewMode === 'story'}>
      <SidePanelTrigger asChild>
        <Button>Open SidePanel with Right Button</Button>
      </SidePanelTrigger>
      <SidePanelContent variant="narrow">
        <SidePanelHeader>
          <SidePanelTitle>Title on Left</SidePanelTitle>
          <ButtonIcon className="ml-auto" size="sm">
            <SvgCog />
          </ButtonIcon>
        </SidePanelHeader>
        <SidePanelScrollArea>
          <PlaceholderContent />
        </SidePanelScrollArea>
      </SidePanelContent>
    </SidePanel>
  ),
}
export const WithStandAloneMobileCloseButton: Story = {
  render: (_args, context) => (
    <SidePanel defaultOpen={context.viewMode === 'story'}>
      <SidePanelTrigger asChild>
        <Button>Open SidePanel with Right Button</Button>
      </SidePanelTrigger>
      <SidePanelContent variant="narrow">
        <SidePanelCloseMobile />
        <SidePanelScrollArea>
          <PlaceholderContent />
        </SidePanelScrollArea>
      </SidePanelContent>
    </SidePanel>
  ),
}

const formComponentsOptions = [
  { label: 'Option 1', value: 'option1' },
  { label: 'Option 2', value: 'option2' },
  { label: 'Option 3', value: 'option3' },
]

const comboboxOptions = [
  {
    value: 'arbitrum',
    label: 'Arbitrum',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/arbitrum.svg?auto=compress%2Cformat',
  },
  {
    value: 'avalanche',
    label: 'Avalanche',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/avalanche.svg?auto=compress%2Cformat',
  },
  {
    value: 'base',
    label: 'Base',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/base.svg?auto=compress%2Cformat',
  },
  {
    value: 'bsc',
    label: 'BNB Chain',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/bsc.svg?auto=compress%2Cformat',
  },
  {
    value: 'celo',
    label: 'Celo',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/celo.svg?auto=compress%2Cformat',
  },
  {
    value: 'ethereum',
    label: 'Ethereum',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/ethereum.svg?auto=compress%2Cformat',
  },
  {
    value: 'fantom',
    label: 'Fantom',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/fantom.svg?auto=compress%2Cformat',
  },
  {
    value: 'gnosis',
    label: 'Gnosis',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/gnosis.svg?auto=compress%2Cformat',
  },
  {
    value: 'kroma',
    label: 'Kroma',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/kroma.svg?auto=compress%2Cformat',
  },
  {
    value: 'linea',
    label: 'Linea',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/linea.svg?auto=compress%2Cformat',
  },
  {
    value: 'mantle',
    label: 'Mantle',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/mantle.svg?auto=compress%2Cformat',
  },
  {
    value: 'metis',
    label: 'Metis',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/metis.svg?auto=compress%2Cformat',
  },
  {
    value: 'mode',
    label: 'Mode',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/mode.svg?auto=compress%2Cformat',
  },
  {
    value: 'moonbeam',
    label: 'Moonbeam',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/moonbeam.svg?auto=compress%2Cformat',
  },
  {
    value: 'moonriver',
    label: 'Moonriver',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/moonriver.svg?auto=compress%2Cformat',
  },
  {
    value: 'optimism',
    label: 'Optimism',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/optimism.svg?auto=compress%2Cformat',
  },
  {
    value: 'polygon',
    label: 'Polygon',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/polygon.svg?auto=compress%2Cformat',
  },
  {
    value: 'polygon-zkevm',
    label: 'Polygon zkEVM',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/polygon-zkevm.svg?auto=compress%2Cformat',
  },
  {
    value: 'scroll',
    label: 'Scroll',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/scroll.svg?auto=compress%2Cformat',
  },
  {
    value: 'wemix',
    label: 'Wemix',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/wemix.svg?auto=compress%2Cformat',
  },
  {
    value: 'zksync',
    label: 'zkSync Era',
    src: 'https://d2f70xi62kby8n.cloudfront.net/bridge/icons/networks/zksync.svg?auto=compress%2Cformat',
  },
]

const multiSelectOptions = [
  { label: 'React', value: 'react' },
  { label: 'Vue', value: 'vue' },
  { label: 'Angular', value: 'angular' },
  { label: 'Svelte', value: 'svelte' },
]

export const WithFormComponents: Story = {
  parameters: {
    // Radix popovers can throw intermittent errors during close animations
    test: { dangerouslyIgnoreUnhandledErrors: true },
  },
  render: (_args, context) => {
    return (
      <SidePanel defaultOpen={context.viewMode === 'story'}>
        <SidePanelTrigger asChild>
          <Button>Open SidePanel with Form Components</Button>
        </SidePanelTrigger>
        <SidePanelContent variant="narrow">
          <SidePanelHeader>
            <SidePanelTitle>Form Components Demo</SidePanelTitle>
          </SidePanelHeader>
          <SidePanelScrollArea>
            <div className="space-y-6 p-6">
              <div className="space-y-2">
                <label className="text-sm font-medium">Select</label>
                <Select>
                  <SelectTrigger className="w-full">
                    <SelectValue placeholder="Select an option" />
                  </SelectTrigger>
                  <SelectContent>
                    {formComponentsOptions.map((option) => (
                      <SelectItem key={option.value} value={option.value}>
                        {option.label}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>

              <div className="space-y-2">
                <label className="text-sm font-medium">MultiSelect</label>
                <MultiSelect
                  options={multiSelectOptions}
                  placeholder="Select frameworks"
                  onValueChange={() => {}}
                />
              </div>

              <div className="space-y-2">
                <label className="text-sm font-medium">LegacyCombobox</label>
                <LegacyCombobox>
                  <LegacyComboboxTrigger className="w-full">
                    <LegacyComboboxValue placeholder="Select network..." />
                  </LegacyComboboxTrigger>
                  <LegacyComboboxContent>
                    {comboboxOptions.map((option) => (
                      <OptionRow key={option.value} value={option.value}>
                        <span className="flex items-center gap-2">
                          <img
                            width="16"
                            height="16"
                            src={option.src}
                            alt={option.label}
                          />
                          {option.label}
                        </span>
                      </OptionRow>
                    ))}
                  </LegacyComboboxContent>
                </LegacyCombobox>
              </div>

              <div className="space-y-2">
                <label className="text-sm font-medium">DropdownMenu</label>
                <DropdownMenu>
                  <DropdownMenuTrigger asChild>
                    <Button variant="secondary" className="w-full">
                      Actions
                    </Button>
                  </DropdownMenuTrigger>
                  <DropdownMenuContent align="start">
                    <DropdownMenuLabel>My Account</DropdownMenuLabel>
                    <DropdownMenuSeparator />
                    <DropdownMenuItem>Profile</DropdownMenuItem>
                    <DropdownMenuItem>Billing</DropdownMenuItem>
                    <DropdownMenuItem>Settings</DropdownMenuItem>
                    <DropdownMenuSeparator />
                    <DropdownMenuItem>Logout</DropdownMenuItem>
                  </DropdownMenuContent>
                </DropdownMenu>
              </div>
            </div>
          </SidePanelScrollArea>
        </SidePanelContent>
      </SidePanel>
    )
  },
  play: async ({ canvasElement: _canvasElement }) => {
    // Wait for SidePanel to be open
    await waitFor(
      async () => {
        const sidePanel = document.querySelector('[role="dialog"]')
        await expect(sidePanel).toBeInTheDocument()
      },
      { timeout: 3000 },
    )

    // Find and click the MultiSelect trigger button to open it
    const multiSelectTrigger = await waitFor(
      async () => {
        const triggers = Array.from(
          document.querySelectorAll('[role="combobox"]'),
        ) as HTMLElement[]
        // Find the MultiSelect trigger by checking if it has the placeholder text
        const trigger = triggers.find((t) =>
          t.getAttribute('aria-label')?.includes('Select frameworks'),
        )
        if (!trigger) {
          throw new Error('MultiSelect trigger not found')
        }
        return trigger
      },
      { timeout: 3000 },
    )

    // Click to open the MultiSelect
    await userEvent.click(multiSelectTrigger)

    // Wait for MultiSelect popover content to be visible
    const multiSelectContent = await waitFor(
      async () => {
        const content = document.querySelector('[role="listbox"]')
        if (!content) {
          throw new Error('MultiSelect content not found')
        }
        return content as HTMLElement
      },
      { timeout: 3000 },
    )

    // Find and click on 'React' option by text content
    const reactOption = await waitFor(
      async () => {
        const options = Array.from(
          multiSelectContent.querySelectorAll('[role="option"]'),
        ) as HTMLElement[]
        const option = options.find((opt) => opt.textContent?.includes('React'))
        if (!option) {
          throw new Error('React option not found')
        }
        return option
      },
      { timeout: 2000 },
    )
    await userEvent.click(reactOption)

    // Wait a bit for the selection to be processed
    await waitFor(
      async () => {
        // Verify React is selected by checking if it has the selected state
        const isSelected = reactOption.getAttribute('aria-selected') === 'true'
        await expect(isSelected).toBe(true)
      },
      { timeout: 1000 },
    )

    // Find and click on 'Vue' option by text content
    const vueOption = await waitFor(
      async () => {
        const options = Array.from(
          multiSelectContent.querySelectorAll('[role="option"]'),
        ) as HTMLElement[]
        const option = options.find((opt) => opt.textContent?.includes('Vue'))
        if (!option) {
          throw new Error('Vue option not found')
        }
        return option
      },
      { timeout: 2000 },
    )
    await userEvent.click(vueOption)

    // Wait a bit for the selection to be processed
    await waitFor(
      async () => {
        // Verify Vue is selected
        const isSelected = vueOption.getAttribute('aria-selected') === 'true'
        await expect(isSelected).toBe(true)
      },
      { timeout: 1000 },
    )

    // Find the search input
    const searchInput = await waitFor(
      async () => {
        const input = multiSelectContent.querySelector(
          'input[aria-label="Search through available options"]',
        ) as HTMLInputElement
        if (!input) {
          throw new Error('Search input not found')
        }
        return input
      },
      { timeout: 2000 },
    )

    // Click on the search input
    await userEvent.click(searchInput)

    // Type 'Svelte' in the search input
    await userEvent.type(searchInput, 'Svelte', { delay: 50 })

    // Wait for the search results to update
    await waitFor(
      async () => {
        // Verify 'Svelte' option is visible in the filtered results
        const options = Array.from(
          multiSelectContent.querySelectorAll('[role="option"]'),
        ) as HTMLElement[]
        const svelteOption = options.find((opt) =>
          opt.textContent?.includes('Svelte'),
        )
        await expect(svelteOption).toBeInTheDocument()
        // Verify the option text contains 'Svelte'
        if (svelteOption) {
          await expect(svelteOption.textContent).toContain('Svelte')
        }
      },
      { timeout: 2000 },
    )

    // Click outside the MultiSelect to close it
    // Find the SidePanel title to click outside
    const sidePanelTitle = await waitFor(
      async () => {
        const title = document.querySelector('[data-slot="sheet-title"]')
        if (!title) {
          throw new Error('SidePanel title not found')
        }
        return title as HTMLElement
      },
      { timeout: 2000 },
    )
    await userEvent.click(sidePanelTitle)

    // Wait for the MultiSelect to close
    await waitFor(
      async () => {
        const content = document.querySelector('[role="listbox"]')
        // The MultiSelect should be closed, so content should not be visible
        await expect(content).not.toBeInTheDocument()
      },
      { timeout: 2000 },
    )

    // Test LegacyCombobox
    // Find and click the LegacyCombobox trigger to open it
    const comboboxTrigger = await waitFor(
      async () => {
        const trigger = document.querySelector(
          '[data-slot="combobox-trigger"]',
        ) as HTMLElement
        if (!trigger) {
          throw new Error('LegacyCombobox trigger not found')
        }
        return trigger
      },
      { timeout: 3000 },
    )

    // Click to open the LegacyCombobox
    await userEvent.click(comboboxTrigger)

    // Wait for the search input to be visible (indicates LegacyCombobox is open)
    const comboboxSearchInput = await waitFor(
      async () => {
        // Wait a bit for the popover to open
        await new Promise((resolve) => setTimeout(resolve, 100))

        const input = document.querySelector(
          'input[placeholder="Search..."]',
        ) as HTMLInputElement

        if (!input) {
          throw new Error('LegacyCombobox search input not found')
        }
        return input
      },
      { timeout: 3000 },
    )

    // Click on the search input to focus it
    await userEvent.click(comboboxSearchInput)

    // Type 'Arb' in the search input
    await userEvent.type(comboboxSearchInput, 'Arb', { delay: 50 })

    // Wait for the search results to update and find the first option
    const firstOption = await waitFor(
      async () => {
        // Wait a bit for the search to filter
        await new Promise((resolve) => setTimeout(resolve, 100))

        // Find options using cmdk-item attribute
        const options = Array.from(
          document.querySelectorAll('[cmdk-item]'),
        ) as HTMLElement[]

        if (options.length === 0) {
          throw new Error('No LegacyCombobox options found after search')
        }

        // Get the first option (should be Arbitrum after filtering)
        const option = options[0]
        await expect(option).toBeInTheDocument()
        return option
      },
      { timeout: 3000 },
    )

    // Click on the first option
    await userEvent.click(firstOption)

    // Wait for the combobox to close after selecting the option
    await waitFor(
      async () => {
        const content = document.querySelector('[data-radix-popover-content]')
        // The combobox should be closed, so content should not be visible
        await expect(content).not.toBeInTheDocument()
      },
      { timeout: 2000 },
    )
  },
}
