import { TextField, InputAdornment, IconButton } from '@mui/material'
import { ClearOutlined, SearchOutlined } from '@mui/icons-material'
import { useEffect, useRef, useCallback } from 'react'
import { widgetStoreActions } from '../../stores/widget-store'
import { useWidgetSelector } from '../../stores/use-widget-selector'
import type { SearcherProps, SearcherFilterFn, SearcherState } from './types'
import type { EchartWidgetData } from '../../echart/types'
import { LOCK_SELECTION_TOOL_ID } from '../lock-selection/lock-selection'

export const SEARCHER_TOOL_ID = 'searcher'

const DEBOUNCE_DELAY = 300

/**
 * Search input component that works with SearcherToggle.
 *
 * Registers a transformation tool in the widget pipeline when mounted.
 * Reads the enabled state from the widget store using the provided id.
 * Uses a debounced search to filter data via the transformation pipeline.
 * Auto-focuses when enabled becomes true.
 *
 * @example
 * ```tsx
 * <SearcherToggle id="my-widget" />
 * <Searcher
 *   id="my-widget"
 *   order={10}
 *   labels={{ placeholder: 'Search categories...' }}
 * />
 * ```
 */
export function Searcher({
  id,
  filterFn,
  order = 20,
  labels,
  TextFieldProps,
  ClearIcon,
  debounceDelay = DEBOUNCE_DELAY,
}: SearcherProps) {
  const inputRef = useRef<HTMLInputElement>(null)
  const debounceTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)

  // Read enabled state and search text from widget store
  const { enabled, searchText } = useWidgetSelector(id, (w) => ({
    enabled: (w as SearcherState | undefined)?.isSearchEnabled ?? false,
    searchText: (w as SearcherState | undefined)?.searchText ?? '',
  }))
  const prevEnabledRef = useRef(enabled)

  const filter = filterFn ?? defaultFilterFn

  const setSearchText = useCallback(
    (text: string) => {
      widgetStoreActions.setWidget(id, { searchText: text })
    },
    [id],
  )

  // Register tool once — fn reads searchText from the store at execution time.
  // Enabled is synced separately to avoid full re-registration on toggle.
  useEffect(() => {
    widgetStoreActions.registerTool(id, {
      id: SEARCHER_TOOL_ID,
      order,
      enabled: false,
      fn: async (data) => {
        const widget = widgetStoreActions.getWidget<SearcherState>(id)
        const currentSearchText = widget?.searchText ?? ''

        // Execute filter (can be sync or async)
        const result = filter(data as EchartWidgetData, currentSearchText)

        // Return result directly (pipeline will handle Promise)
        return result
      },
      disables: [LOCK_SELECTION_TOOL_ID],
    })

    return () => widgetStoreActions.unregisterTool(id, SEARCHER_TOOL_ID)
  }, [id, order, filter])

  // Sync enabled from store — lightweight, no re-registration
  useEffect(() => {
    widgetStoreActions.setToolEnabled(id, SEARCHER_TOOL_ID, enabled)
  }, [id, enabled])

  // Trigger pipeline re-execution when search text changes (debounced).
  // The fn reads searchText from the store, so we just need to trigger the pipeline.
  const debouncedTriggerPipeline = useCallback(() => {
    if (debounceTimeoutRef.current) {
      clearTimeout(debounceTimeoutRef.current)
    }
    debounceTimeoutRef.current = setTimeout(() => {
      widgetStoreActions.triggerToolPipeline(id)
    }, debounceDelay)
  }, [id, debounceDelay])

  // Auto-focus when enabled becomes true
  useEffect(() => {
    // Transition from disabled to enabled - focus input
    if (enabled && !prevEnabledRef.current && inputRef.current) {
      inputRef.current.focus()
    }

    prevEnabledRef.current = enabled
  }, [enabled])

  // Cleanup debounce timeout on unmount
  useEffect(() => {
    return () => {
      if (debounceTimeoutRef.current) {
        clearTimeout(debounceTimeoutRef.current)
      }
    }
  }, [])

  const handleChange = useCallback(
    (event: React.ChangeEvent<HTMLInputElement>) => {
      const newValue = event.target.value
      setSearchText(newValue)
      debouncedTriggerPipeline()
    },
    [debouncedTriggerPipeline, setSearchText],
  )

  const handleClear = useCallback(() => {
    setSearchText('')
    widgetStoreActions.triggerToolPipeline(id)
    if (inputRef.current) {
      inputRef.current.focus()
    }
  }, [id, setSearchText])

  if (!enabled) {
    return null
  }

  const placeholder = labels?.placeholder ?? 'Search...'
  const clearAriaLabel = labels?.clearAriaLabel ?? 'Clear search'

  return (
    <TextField
      inputRef={inputRef}
      size='small'
      fullWidth
      variant='filled'
      placeholder={placeholder}
      value={searchText}
      onChange={handleChange}
      InputProps={{
        startAdornment: (
          <InputAdornment position='start'>
            <SearchOutlined />
          </InputAdornment>
        ),
        endAdornment: searchText ? (
          <InputAdornment position='end'>
            <IconButton
              size='small'
              aria-label={clearAriaLabel}
              onClick={handleClear}
              edge='end'
            >
              {ClearIcon ?? <ClearOutlined fontSize='small' />}
            </IconButton>
          </InputAdornment>
        ) : null,
      }}
      {...TextFieldProps}
    />
  )
}

/**
 * Default filter function that searches all string fields case-insensitively.
 * Note: Should be synchronous for the new pipeline architecture.
 */
const defaultFilterFn: SearcherFilterFn = (
  data: EchartWidgetData,
  searchText: string,
) => {
  if (!searchText.trim()) return Promise.resolve(data)

  const lowerSearch = searchText.toLowerCase()

  return Promise.resolve(
    data.map((series) =>
      series.filter((item) =>
        Object.values(item).some((value) =>
          String(value).toLowerCase().includes(lowerSearch),
        ),
      ),
    ),
  )
}
