import { describe, test, expect } from 'vitest'
import { render, screen, fireEvent } from '@testing-library/react'
import { ToolbarActions } from './toolbar-actions'
import { IconButton, Divider } from '@mui/material'
import { Tooltip } from '../../components/tooltip/tooltip'
import {
  FileDownloadOutlined,
  ShareOutlined,
  EditOutlined,
  FilterListOutlined,
} from '@mui/icons-material'

describe('ToolbarActions', () => {
  const createAction = (
    key: string,
    label: string,
    Icon: React.ComponentType,
  ) => (
    <Tooltip key={key} title={label}>
      <IconButton size='small' aria-label={label}>
        <Icon />
      </IconButton>
    </Tooltip>
  )

  describe('data-toolbar-hidden filtering', () => {
    test('filters children with data-toolbar-hidden from visible count', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        <Divider
          key='divider-1'
          orientation='vertical'
          flexItem
          data-toolbar-hidden
        />,
        createAction('share', 'Share', ShareOutlined),
        <Divider
          key='divider-2'
          orientation='vertical'
          flexItem
          data-toolbar-hidden
        />,
        createAction('edit', 'Edit', EditOutlined),
      ]

      render(<ToolbarActions visibleCount={2}>{children}</ToolbarActions>)

      // Should show trigger button because there are 3 visible actions (download, share, edit)
      // even though total children count is 5
      const triggerButton = screen.getByRole('button', {
        name: /more actions/i,
      })
      expect(triggerButton).toBeTruthy()

      // Preview should include first 2 visible actions plus divider between them
      // (Download, Divider, Share - stops after counting 2 non-hidden actions)
      const downloadButtons = screen.getAllByLabelText('Download')
      const shareButtons = screen.getAllByLabelText('Share')
      expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
      expect(shareButtons.length).toBeGreaterThanOrEqual(1)

      // Edit button should also be present (in the expanded section)
      const editButtons = screen.getAllByLabelText('Edit')
      expect(editButtons.length).toBeGreaterThanOrEqual(1)
    })

    test('includes data-toolbar-hidden children in preview between visible actions', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        <Divider
          key='divider-1'
          orientation='vertical'
          flexItem
          data-toolbar-hidden
          data-testid='divider-1'
        />,
        createAction('share', 'Share', ShareOutlined),
        <Divider
          key='divider-2'
          orientation='vertical'
          flexItem
          data-toolbar-hidden
          data-testid='divider-2'
        />,
        createAction('edit', 'Edit', EditOutlined),
      ]

      const { container } = render(
        <ToolbarActions visibleCount={2}>{children}</ToolbarActions>,
      )

      // With visibleCount={2}, preview should include:
      // Download, Divider-1, Share (counting 2 visible actions, including divider between them)
      // Hidden: Divider-2, Edit

      // First divider should be visible (in both preview and expanded)
      const allDividers = container.querySelectorAll(
        '[data-toolbar-hidden="true"]',
      )
      expect(allDividers.length).toBeGreaterThanOrEqual(1)
    })

    test('includes hidden children in expanded view', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        <Divider
          key='divider-1'
          orientation='vertical'
          flexItem
          data-toolbar-hidden
        />,
        createAction('share', 'Share', ShareOutlined),
        <Divider
          key='divider-2'
          orientation='vertical'
          flexItem
          data-toolbar-hidden
        />,
        createAction('edit', 'Edit', EditOutlined),
      ]

      const { container } = render(
        <ToolbarActions visibleCount={2}>{children}</ToolbarActions>,
      )

      const triggerButton = screen.getByRole('button', {
        name: /more actions/i,
      })
      fireEvent.click(triggerButton)

      // After expanding, all children including dividers should be present
      // Check for dividers with data-toolbar-hidden attribute
      // Note: dividers appear in both preview and expanded sections
      // Preview: Divider-1 (between Download and Share)
      // Expanded: Divider-1 and Divider-2 (all dividers)
      // Total: 3 dividers with data-toolbar-hidden attribute
      const dividers = container.querySelectorAll(
        '[data-toolbar-hidden="true"]',
      )
      expect(dividers.length).toBe(3) // Divider-1 (preview) + Divider-1 + Divider-2 (expanded)
    })

    test('does not show trigger when only hidden children exceed visibleCount', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        createAction('share', 'Share', ShareOutlined),
        <Divider
          key='divider-1'
          orientation='vertical'
          flexItem
          data-toolbar-hidden
        />,
        <Divider
          key='divider-2'
          orientation='vertical'
          flexItem
          data-toolbar-hidden
        />,
      ]

      render(<ToolbarActions visibleCount={2}>{children}</ToolbarActions>)

      // Should not show trigger button because there are only 2 visible actions
      const triggerButtons = screen.queryAllByRole('button', {
        name: /more actions/i,
      })
      expect(triggerButtons.length).toBe(0)

      // Both visible actions should be shown (appear in both preview and hidden expanded sections)
      const downloadButtons = screen.getAllByLabelText('Download')
      const shareButtons = screen.getAllByLabelText('Share')
      expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
      expect(shareButtons.length).toBeGreaterThanOrEqual(1)
    })
  })

  describe('visibleCount behavior', () => {
    test('shows all actions when visibleCount is undefined', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        createAction('share', 'Share', ShareOutlined),
        createAction('edit', 'Edit', EditOutlined),
        createAction('filter', 'Filter', FilterListOutlined),
      ]

      render(
        <ToolbarActions visibleCount={undefined}>{children}</ToolbarActions>,
      )

      // Should not show trigger button
      const triggerButtons = screen.queryAllByRole('button', {
        name: /more actions/i,
      })
      expect(triggerButtons.length).toBe(0)

      // All actions should be visible (appear in both preview and hidden expanded sections)
      const downloadButtons = screen.getAllByLabelText('Download')
      const shareButtons = screen.getAllByLabelText('Share')
      const editButtons = screen.getAllByLabelText('Edit')
      const filterButtons = screen.getAllByLabelText('Filter')
      expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
      expect(shareButtons.length).toBeGreaterThanOrEqual(1)
      expect(editButtons.length).toBeGreaterThanOrEqual(1)
      expect(filterButtons.length).toBeGreaterThanOrEqual(1)
    })

    test('shows trigger when visibleCount is 1 and there are 2+ actions', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        createAction('share', 'Share', ShareOutlined),
      ]

      render(<ToolbarActions visibleCount={1}>{children}</ToolbarActions>)

      // Should show trigger button
      const triggerButton = screen.getByRole('button', {
        name: /more actions/i,
      })
      expect(triggerButton).toBeTruthy()

      // Download action should be visible (appears in both preview and expanded)
      const downloadButtons = screen.getAllByLabelText('Download')
      expect(downloadButtons.length).toBeGreaterThanOrEqual(1)

      // Share button exists in the expanded section
      const shareButtons = screen.getAllByLabelText('Share')
      expect(shareButtons.length).toBeGreaterThanOrEqual(1)
    })

    test('shows trigger when visibleCount is 2 and there are 3+ actions', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        createAction('share', 'Share', ShareOutlined),
        createAction('edit', 'Edit', EditOutlined),
      ]

      render(<ToolbarActions visibleCount={2}>{children}</ToolbarActions>)

      // Should show trigger button
      const triggerButton = screen.getByRole('button', {
        name: /more actions/i,
      })
      expect(triggerButton).toBeTruthy()

      // First two actions should be visible (appear in both preview and expanded)
      const downloadButtons = screen.getAllByLabelText('Download')
      const shareButtons = screen.getAllByLabelText('Share')
      expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
      expect(shareButtons.length).toBeGreaterThanOrEqual(1)
    })

    test('does not show trigger when actions equal visibleCount', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        createAction('share', 'Share', ShareOutlined),
      ]

      render(<ToolbarActions visibleCount={2}>{children}</ToolbarActions>)

      // Should not show trigger button
      const triggerButtons = screen.queryAllByRole('button', {
        name: /more actions/i,
      })
      expect(triggerButtons.length).toBe(0)

      // Both actions should be visible (appear in both preview and hidden expanded sections)
      const downloadButtons = screen.getAllByLabelText('Download')
      const shareButtons = screen.getAllByLabelText('Share')
      expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
      expect(shareButtons.length).toBeGreaterThanOrEqual(1)
    })

    test('does not show trigger when actions are less than visibleCount', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
      ]

      render(<ToolbarActions visibleCount={2}>{children}</ToolbarActions>)

      // Should not show trigger button
      const triggerButtons = screen.queryAllByRole('button', {
        name: /more actions/i,
      })
      expect(triggerButtons.length).toBe(0)

      // Single action should be visible (appears in both preview and hidden expanded sections)
      const downloadButtons = screen.getAllByLabelText('Download')
      expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
    })
  })

  describe('trigger button behavior', () => {
    test('trigger button appears when there are more visible actions than visibleCount', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        createAction('share', 'Share', ShareOutlined),
        createAction('edit', 'Edit', EditOutlined),
      ]

      render(<ToolbarActions visibleCount={2}>{children}</ToolbarActions>)

      const triggerButton = screen.getByRole('button', {
        name: /more actions/i,
      })
      expect(triggerButton).toBeTruthy()
    })

    test('trigger button does not appear when visibleCount is undefined', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        createAction('share', 'Share', ShareOutlined),
        createAction('edit', 'Edit', EditOutlined),
      ]

      render(
        <ToolbarActions visibleCount={undefined}>{children}</ToolbarActions>,
      )

      const triggerButtons = screen.queryAllByRole('button', {
        name: /more actions/i,
      })
      expect(triggerButtons.length).toBe(0)
    })

    test('clicking trigger button expands the actions panel', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        createAction('share', 'Share', ShareOutlined),
        createAction('edit', 'Edit', EditOutlined),
      ]

      render(<ToolbarActions visibleCount={2}>{children}</ToolbarActions>)

      const triggerButton = screen.getByRole('button', {
        name: /more actions/i,
      })

      // Before clicking, trigger button should not have data-active
      expect(triggerButton.getAttribute('data-active')).toBe('false')

      fireEvent.click(triggerButton)

      // After clicking, trigger button should have data-active
      expect(triggerButton.getAttribute('data-active')).toBe('true')

      // Button should now show close label
      const closeButton = screen.getByRole('button', { name: /close/i })
      expect(closeButton).toBeTruthy()
    })

    test('clicking trigger button again collapses the actions panel', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        createAction('share', 'Share', ShareOutlined),
        createAction('edit', 'Edit', EditOutlined),
      ]

      render(<ToolbarActions visibleCount={2}>{children}</ToolbarActions>)

      const triggerButton = screen.getByRole('button', {
        name: /more actions/i,
      })

      // Expand
      fireEvent.click(triggerButton)
      expect(triggerButton.getAttribute('data-active')).toBe('true')

      // Collapse
      fireEvent.click(triggerButton)
      expect(triggerButton.getAttribute('data-active')).toBe('false')

      // Button should show trigger label again
      const reopenButton = screen.getByRole('button', {
        name: /more actions/i,
      })
      expect(reopenButton).toBeTruthy()
    })

    test('uses custom labels when provided', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        createAction('share', 'Share', ShareOutlined),
        createAction('edit', 'Edit', EditOutlined),
      ]

      render(
        <ToolbarActions
          visibleCount={2}
          labels={{ trigger: 'Show options', close: 'Hide options' }}
        >
          {children}
        </ToolbarActions>,
      )

      const triggerButton = screen.getByRole('button', {
        name: /show options/i,
      })
      expect(triggerButton).toBeTruthy()

      fireEvent.click(triggerButton)

      const closeButton = screen.getByRole('button', { name: /hide options/i })
      expect(closeButton).toBeTruthy()
    })
  })

  describe('childrenPreview behavior', () => {
    test('childrenPreview shows only visible children up to visibleCount', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        createAction('share', 'Share', ShareOutlined),
        createAction('edit', 'Edit', EditOutlined),
        createAction('filter', 'Filter', FilterListOutlined),
      ]

      render(<ToolbarActions visibleCount={2}>{children}</ToolbarActions>)

      // Only first 2 should be in preview
      // Note: Download and Share appear in both preview and expanded sections
      const downloadButtons = screen.getAllByLabelText('Download')
      const shareButtons = screen.getAllByLabelText('Share')
      expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
      expect(shareButtons.length).toBeGreaterThanOrEqual(1)

      // Edit and Filter should also be in expanded section
      const triggerButton = screen.getByRole('button', {
        name: /more actions/i,
      })
      fireEvent.click(triggerButton)

      // Now all should be visible
      const editButtons = screen.getAllByLabelText('Edit')
      const filterButtons = screen.getAllByLabelText('Filter')
      expect(editButtons.length).toBeGreaterThanOrEqual(1)
      expect(filterButtons.length).toBeGreaterThanOrEqual(1)
    })

    test('childrenPreview includes hidden children but does not count them', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        <Divider
          key='divider-1'
          orientation='vertical'
          flexItem
          data-toolbar-hidden
        />,
        createAction('share', 'Share', ShareOutlined),
        createAction('edit', 'Edit', EditOutlined),
      ]

      const { container } = render(
        <ToolbarActions visibleCount={2}>{children}</ToolbarActions>,
      )

      // Preview should show: Download, Divider, Share (2 visible actions counted, divider included)
      // Hidden: Edit action
      const downloadButtons = screen.getAllByLabelText('Download')
      const shareButtons = screen.getAllByLabelText('Share')
      expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
      expect(shareButtons.length).toBeGreaterThanOrEqual(1)

      // Divider with data-toolbar-hidden should be in preview (appears in both preview and expanded)
      const allDividers = container.querySelectorAll(
        '[data-toolbar-hidden="true"]',
      )
      expect(allDividers.length).toBeGreaterThanOrEqual(1)

      // Edit button should also be present in expanded section
      const triggerButton = screen.getByRole('button', {
        name: /more actions/i,
      })
      fireEvent.click(triggerButton)

      const editButtons = screen.getAllByLabelText('Edit')
      expect(editButtons.length).toBeGreaterThanOrEqual(1)
    })

    test('childrenPreview shows all visible children when visibleCount is undefined', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        createAction('share', 'Share', ShareOutlined),
        createAction('edit', 'Edit', EditOutlined),
      ]

      render(
        <ToolbarActions visibleCount={undefined}>{children}</ToolbarActions>,
      )

      // All actions should be in preview (no trigger button)
      // Actions appear in both preview and hidden expanded sections
      const downloadButtons = screen.getAllByLabelText('Download')
      const shareButtons = screen.getAllByLabelText('Share')
      const editButtons = screen.getAllByLabelText('Edit')
      expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
      expect(shareButtons.length).toBeGreaterThanOrEqual(1)
      expect(editButtons.length).toBeGreaterThanOrEqual(1)

      const triggerButtons = screen.queryAllByRole('button', {
        name: /more actions/i,
      })
      expect(triggerButtons.length).toBe(0)
    })
  })

  describe('edge cases', () => {
    test('renders nothing when children array is empty', () => {
      const { container } = render(<ToolbarActions>{[]}</ToolbarActions>)
      expect(container.firstChild).toBeNull()
    })

    test('renders nothing when children is null', () => {
      const { container } = render(<ToolbarActions>{null}</ToolbarActions>)
      expect(container.firstChild).toBeNull()
    })

    test('handles single child (not array)', () => {
      const child = createAction('download', 'Download', FileDownloadOutlined)

      render(<ToolbarActions visibleCount={2}>{child}</ToolbarActions>)

      // Should appear in both preview and expanded sections (even though expanded is hidden)
      const downloadButtons = screen.getAllByLabelText('Download')
      expect(downloadButtons.length).toBeGreaterThanOrEqual(1)

      const triggerButtons = screen.queryAllByRole('button', {
        name: /more actions/i,
      })
      expect(triggerButtons.length).toBe(0)
    })

    test('handles all children being hidden', () => {
      const children = [
        <Divider
          key='divider-1'
          orientation='vertical'
          flexItem
          data-toolbar-hidden
        />,
        <Divider
          key='divider-2'
          orientation='vertical'
          flexItem
          data-toolbar-hidden
        />,
      ]

      const { container } = render(
        <ToolbarActions visibleCount={2}>{children}</ToolbarActions>,
      )

      // Component still renders container even when no visible children
      // (it only checks children.length, not visibleChildren.length)
      // This test documents the current behavior
      expect(container.firstChild).toBeTruthy()

      // But there should be no trigger button since visibleChildren.length is 0
      const triggerButtons = screen.queryAllByRole('button', {
        name: /more actions/i,
      })
      expect(triggerButtons.length).toBe(0)
    })

    test('correctly counts when mix of hidden and visible children', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        <Divider
          key='d1'
          orientation='vertical'
          flexItem
          data-toolbar-hidden
        />,
        createAction('share', 'Share', ShareOutlined),
        <Divider
          key='d2'
          orientation='vertical'
          flexItem
          data-toolbar-hidden
        />,
        createAction('edit', 'Edit', EditOutlined),
        <Divider
          key='d3'
          orientation='vertical'
          flexItem
          data-toolbar-hidden
        />,
        createAction('filter', 'Filter', FilterListOutlined),
      ]

      render(<ToolbarActions visibleCount={3}>{children}</ToolbarActions>)

      // Should show trigger because there are 4 visible actions > 3
      const triggerButton = screen.getByRole('button', {
        name: /more actions/i,
      })
      expect(triggerButton).toBeTruthy()

      // Preview should show first 3 visible actions + dividers between them
      // (Download, Divider, Share, Divider, Edit - stops after counting 3 non-hidden)
      const downloadButtons = screen.getAllByLabelText('Download')
      const shareButtons = screen.getAllByLabelText('Share')
      const editButtons = screen.getAllByLabelText('Edit')
      expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
      expect(shareButtons.length).toBeGreaterThanOrEqual(1)
      expect(editButtons.length).toBeGreaterThanOrEqual(1)
    })

    test('documentation example: visibleCount={2} with [Action1, Divider, Action2, Divider, Action3]', () => {
      const children = [
        createAction('action1', 'Action 1', FileDownloadOutlined),
        <Divider
          key='divider-1'
          orientation='vertical'
          flexItem
          data-toolbar-hidden
        />,
        createAction('action2', 'Action 2', ShareOutlined),
        <Divider
          key='divider-2'
          orientation='vertical'
          flexItem
          data-toolbar-hidden
        />,
        createAction('action3', 'Action 3', EditOutlined),
      ]

      const { container } = render(
        <ToolbarActions visibleCount={2}>{children}</ToolbarActions>,
      )

      // Expected preview: Action1, Divider, Action2 (2 actions counted, divider included)
      // Hidden: Divider, Action3

      // Should show trigger button since we have 3 visible actions > 2
      const triggerButton = screen.getByRole('button', {
        name: /more actions/i,
      })
      expect(triggerButton).toBeTruthy()

      // Action1 and Action2 should be visible
      const action1Buttons = screen.getAllByLabelText('Action 1')
      const action2Buttons = screen.getAllByLabelText('Action 2')
      expect(action1Buttons.length).toBeGreaterThanOrEqual(1)
      expect(action2Buttons.length).toBeGreaterThanOrEqual(1)

      // At least one divider with data-toolbar-hidden should be rendered
      const dividers = container.querySelectorAll(
        '[data-toolbar-hidden="true"]',
      )
      expect(dividers.length).toBeGreaterThanOrEqual(1)

      // Action3 should be in expanded section
      const action3Buttons = screen.getAllByLabelText('Action 3')
      expect(action3Buttons.length).toBeGreaterThanOrEqual(1)
    })
  })

  describe('direction prop', () => {
    test('applies correct flex direction for left expansion', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        createAction('share', 'Share', ShareOutlined),
      ]

      const { container } = render(
        <ToolbarActions direction='left'>{children}</ToolbarActions>,
      )

      const root = container.firstChild as HTMLElement
      expect(root).toBeTruthy()
      // Check that the style contains row-reverse
      const style = window.getComputedStyle(root)
      expect(style.flexDirection).toBe('row-reverse')
    })

    test('applies correct flex direction for right expansion (default)', () => {
      const children = [
        createAction('download', 'Download', FileDownloadOutlined),
        createAction('share', 'Share', ShareOutlined),
      ]

      const { container } = render(
        <ToolbarActions direction='right'>{children}</ToolbarActions>,
      )

      const root = container.firstChild as HTMLElement
      expect(root).toBeTruthy()
      const style = window.getComputedStyle(root)
      expect(style.flexDirection).toBe('row')
    })
  })
})
