import { describe, test, expect, beforeEach, vi, afterEach } from 'vitest'
import { render, screen, fireEvent, act } from '@testing-library/react'
import { SearcherToggle } from './searcher-toggle'
import { Searcher } from './searcher'
import { useWidgetStore } from '../../stores/widget-store'
import type { EchartWidgetData } from '../../echart/types'
import type { SearcherState } from './types'

// Test data
const mockData: EchartWidgetData = [
  [
    { name: 'Electronics', value: 440 },
    { name: 'Clothing', value: 280 },
    { name: 'Books', value: 100 },
  ],
]

describe('SearcherToggle', () => {
  const widgetId = 'test-searcher-toggle'

  beforeEach(() => {
    useWidgetStore.getState().clearWidgets()
  })

  test('renders search toggle button', () => {
    render(<SearcherToggle id={widgetId} />)

    const button = screen.getByRole('button')
    expect(button).toBeTruthy()
  })

  test('shows enable tooltip when search is disabled', () => {
    render(<SearcherToggle id={widgetId} />)

    const button = screen.getByRole('button', { name: 'Enable search' })
    expect(button).toBeTruthy()
  })

  test('shows disable tooltip when search is enabled', () => {
    render(<SearcherToggle id={widgetId} defaultEnabled />)

    const button = screen.getByRole('button', { name: 'Disable search' })
    expect(button).toBeTruthy()
  })

  test('toggles isSearchEnabled in store when clicked', () => {
    render(<SearcherToggle id={widgetId} />)

    const button = screen.getByRole('button')
    fireEvent.click(button)

    const widget = useWidgetStore.getState().getWidget<SearcherState>(widgetId)
    expect(widget?.isSearchEnabled).toBe(true)
  })

  test('has active state when enabled via store', () => {
    render(<SearcherToggle id={widgetId} defaultEnabled />)

    const button = screen.getByRole('button')
    expect(button.getAttribute('data-active')).toBe('true')
  })

  test('has inactive state when disabled', () => {
    render(<SearcherToggle id={widgetId} />)

    const button = screen.getByRole('button')
    expect(button.getAttribute('data-active')).toBe('false')
  })

  test('uses custom labels', () => {
    render(
      <SearcherToggle
        id={widgetId}
        labels={{
          enable: 'Activar búsqueda',
          disable: 'Desactivar búsqueda',
          ariaLabel: 'Toggle search',
        }}
      />,
    )

    const button = screen.getByRole('button', { name: 'Toggle search' })
    expect(button).toBeTruthy()
  })

  test('initializes store with defaultEnabled value', () => {
    render(<SearcherToggle id={widgetId} defaultEnabled />)

    const widget = useWidgetStore.getState().getWidget<SearcherState>(widgetId)
    expect(widget?.isSearchEnabled).toBe(true)
  })
})

describe('Searcher', () => {
  const widgetId = 'test-searcher-input'

  beforeEach(() => {
    useWidgetStore.getState().clearWidgets()
    vi.useFakeTimers()
  })

  afterEach(() => {
    vi.useRealTimers()
  })

  test('does not render when search is disabled in store', () => {
    // Set isSearchEnabled to false in store
    useWidgetStore.getState().setWidget(widgetId, { isSearchEnabled: false })

    render(<Searcher id={widgetId} />)

    const input = screen.queryByRole('textbox')
    expect(input).toBeNull()
  })

  test('renders input when search is enabled in store', () => {
    // Set isSearchEnabled to true in store
    useWidgetStore.getState().setWidget(widgetId, { isSearchEnabled: true })

    render(<Searcher id={widgetId} />)

    const input = screen.getByRole('textbox')
    expect(input).toBeTruthy()
  })

  test('shows placeholder text', () => {
    useWidgetStore.getState().setWidget(widgetId, { isSearchEnabled: true })

    render(<Searcher id={widgetId} labels={{ placeholder: 'Search...' }} />)

    const input = screen.getByPlaceholderText('Search...')
    expect(input).toBeTruthy()
  })

  test('updates store with debounced filtered data', async () => {
    // Initialize widget with data and enabled state
    useWidgetStore
      .getState()
      .setWidget(widgetId, { data: mockData, isSearchEnabled: true })

    render(<Searcher id={widgetId} />)

    const input = screen.getByRole('textbox')
    fireEvent.change(input, { target: { value: 'Electronics' } })

    // Wait for debounce (300ms) and flush all pending promises
    await act(async () => {
      await vi.advanceTimersByTimeAsync(300)
    })

    // Execute the tool pipeline to apply the filter transformation
    await useWidgetStore.getState().executeToolPipeline(widgetId, mockData)

    const widget = useWidgetStore.getState().getWidget(widgetId)
    const filteredData = widget?.data as EchartWidgetData | undefined

    // Should only have Electronics item
    expect(filteredData?.[0]?.length).toBe(1)
    expect(filteredData?.[0]?.[0]?.name).toBe('Electronics')
  })

  test('shows clear button when there is text', () => {
    useWidgetStore.getState().setWidget(widgetId, { isSearchEnabled: true })

    render(<Searcher id={widgetId} />)

    const input = screen.getByRole('textbox')
    fireEvent.change(input, { target: { value: 'test' } })

    const clearButton = screen.getByRole('button', { name: 'Clear search' })
    expect(clearButton).toBeTruthy()
  })

  test('does not show clear button when input is empty', () => {
    useWidgetStore.getState().setWidget(widgetId, { isSearchEnabled: true })

    render(<Searcher id={widgetId} />)

    const clearButton = screen.queryByRole('button', { name: 'Clear search' })
    expect(clearButton).toBeNull()
  })

  test('clears search text and restores original data when clear button is clicked', () => {
    // Initialize widget with data and enabled state
    useWidgetStore
      .getState()
      .setWidget(widgetId, { data: mockData, isSearchEnabled: true })

    render(<Searcher id={widgetId} />)

    const input = screen.getByRole('textbox')
    fireEvent.change(input, { target: { value: 'Electronics' } })

    // Wait for debounce
    act(() => {
      vi.advanceTimersByTime(300)
    })

    // Click clear
    const clearButton = screen.getByRole('button', { name: 'Clear search' })
    fireEvent.click(clearButton)

    // Data should be restored to original
    const widget = useWidgetStore.getState().getWidget(widgetId)
    const restoredData = widget?.data as EchartWidgetData | undefined
    expect(restoredData?.[0]?.length).toBe(3)
  })

  test('uses custom clear button aria label', () => {
    useWidgetStore.getState().setWidget(widgetId, { isSearchEnabled: true })

    render(
      <Searcher
        id={widgetId}
        labels={{ clearAriaLabel: 'Limpiar búsqueda' }}
      />,
    )

    const input = screen.getByRole('textbox')
    fireEvent.change(input, { target: { value: 'text' } })

    const clearButton = screen.getByRole('button', {
      name: 'Limpiar búsqueda',
    })
    expect(clearButton).toBeTruthy()
  })

  test('uses custom filter function', async () => {
    // Custom filter that only matches exact values
    const customFilterFn = async (
      data: EchartWidgetData,
      searchText: string,
    ) => {
      return Promise.resolve(
        data.map((series) =>
          series.filter((item) => item.value === parseInt(searchText, 10)),
        ),
      )
    }

    // Initialize widget with data and enabled state
    useWidgetStore
      .getState()
      .setWidget(widgetId, { data: mockData, isSearchEnabled: true })

    render(<Searcher id={widgetId} filterFn={customFilterFn} />)

    const input = screen.getByRole('textbox')
    fireEvent.change(input, { target: { value: '440' } })

    // Wait for debounce and flush all pending promises
    await act(async () => {
      await vi.advanceTimersByTimeAsync(300)
    })

    // Execute the tool pipeline to apply the filter transformation
    await useWidgetStore.getState().executeToolPipeline(widgetId, mockData)

    // Should only have Electronics (value: 440)
    const widget = useWidgetStore.getState().getWidget(widgetId)
    const filteredData = widget?.data as EchartWidgetData | undefined
    expect(filteredData?.[0]?.length).toBe(1)
    expect(filteredData?.[0]?.[0]?.value).toBe(440)
  })
})

describe('SearcherToggle + Searcher integration', () => {
  const widgetId = 'test-integration'

  beforeEach(() => {
    useWidgetStore.getState().clearWidgets()
  })

  // Helper component that uses both SearcherToggle and Searcher with same id
  function IntegrationTest() {
    return (
      <>
        <SearcherToggle id={widgetId} />
        <Searcher id={widgetId} />
      </>
    )
  }

  test('searcher becomes visible when toggle is clicked', () => {
    render(<IntegrationTest />)

    // Initially searcher should not be visible
    expect(screen.queryByRole('textbox')).toBeNull()

    // Click toggle
    const toggleButton = screen.getByRole('button')
    fireEvent.click(toggleButton)

    // Searcher should now be visible
    expect(screen.getByRole('textbox')).toBeTruthy()
  })

  test('searcher is hidden when toggle is clicked again', () => {
    render(<IntegrationTest />)

    const toggleButton = screen.getByRole('button')

    // Enable
    fireEvent.click(toggleButton)
    expect(screen.getByRole('textbox')).toBeTruthy()

    // Disable
    fireEvent.click(toggleButton)
    expect(screen.queryByRole('textbox')).toBeNull()
  })

  test('toggle button shows correct active state', () => {
    render(<IntegrationTest />)

    const toggleButton = screen.getByRole('button')

    // Initially inactive
    expect(toggleButton.getAttribute('data-active')).toBe('false')

    // Enable - should be active
    fireEvent.click(toggleButton)
    expect(toggleButton.getAttribute('data-active')).toBe('true')

    // Disable - should be inactive
    fireEvent.click(toggleButton)
    expect(toggleButton.getAttribute('data-active')).toBe('false')
  })

  test('store state is correctly updated when toggling', () => {
    render(<IntegrationTest />)

    const toggleButton = screen.getByRole('button')

    // Initially should be false
    expect(
      useWidgetStore.getState().getWidget<SearcherState>(widgetId)
        ?.isSearchEnabled,
    ).toBe(false)

    // Enable
    fireEvent.click(toggleButton)
    expect(
      useWidgetStore.getState().getWidget<SearcherState>(widgetId)
        ?.isSearchEnabled,
    ).toBe(true)

    // Disable
    fireEvent.click(toggleButton)
    expect(
      useWidgetStore.getState().getWidget<SearcherState>(widgetId)
        ?.isSearchEnabled,
    ).toBe(false)
  })
})
