import React, { useCallback, useEffect, useRef, useState } from 'react'
import { Cell, Row, StickyTable } from 'react-sticky-table'

import styles from './_treeListBox.module.scss'
import tableStyles from '../TableComponents/_table.module.scss'
import CheckboxList from './CheckboxList'
import EmptyState from '../EmptyState/EmptyState'
import ListLoading from '../Loaders/ListLoading'
import SearchBar from '../SearchBar/SearchBar'
import StickyTableContainer from '../TableComponents/StickyTableContainer'
import UnsortedColumn from '../UnsortedColumn/UnsortedColumn'
import { type EmptyStateProps } from '../EmptyState/EmptyState'
import { c } from '../../translations/LibraryTranslationService'
import {
  CheckboxState,
  debouncedSearchRefactored,
  type FlattenNestedDataProps,
  type GenericNode,
  type NestedCheckboxProps,
  toggleExpand,
  updateItemStates,
} from '../Form/NestedCheckboxHelper'

type TreeListBoxProps = NestedCheckboxProps<GenericNode>

function TreeListBox({
  data,
  hasData,
  isLoading,
  tableConfig,
  noDataText,
  identifierKeys,
  isSearchable = false,
  customHeight,
  customWidth,
  onChange,
  setItemStates,
  itemStates,
  search,
  qaTestId = 'tree-list-box',
  ignoreNodeHierarchy = false,
}: TreeListBoxProps) {
  const { displayKey, idKey, parentKey } = identifierKeys

  const noDataTextProps = noDataText ?? {
    primaryText: c('noDataAvailable'),
  }

  const [expandedItems, setExpandedItems] = useState<{
    [key: string]: boolean
  }>({})
  // TODO: Remove this state once search prop is implemented all instances of TreeListBox
  const [searchQuery, setSearchQuery] = useState('')
  const [filteredItems, setFilteredItems] =
    useState<FlattenNestedDataProps[]>(data)

  // Track checkbox interactions to prevent search re-runs
  const isCheckboxInteraction = useRef(false)
  const searchDataDependencies = useRef<{ data: any[]; query: string }>({
    data: [],
    query: '',
  })

  // Add state to track search loading state
  const [isSearching, setIsSearching] = useState(false)

  const getStateForId = useCallback(
    (id: string | number) => {
      return (
        itemStates?.find((i) => i.id === id)?.state || CheckboxState.UNCHECKED
      )
    },
    [itemStates],
  )

  const clickHandler = useCallback(
    (id: string | number) => {
      // Set flag to indicate checkbox interaction
      isCheckboxInteraction.current = true

      const newState = updateItemStates(
        ignoreNodeHierarchy,
        itemStates,
        data,
        id,
        idKey,
        parentKey,
      )
      setItemStates(newState)
      onChange?.(newState)

      // Clear the flag after a short delay
      setTimeout(() => {
        isCheckboxInteraction.current = false
      }, 150)
    },
    [
      data,
      idKey,
      itemStates,
      onChange,
      parentKey,
      setItemStates,
      ignoreNodeHierarchy,
    ],
  )

  const onToggleExpand = useCallback(
    (idOrIds: string | number | (string | number)[]) => {
      toggleExpand(idOrIds, setExpandedItems)
    },
    [],
  )

  useEffect(() => {
    // TODO: Remove searchQuery once search prop is implemented at all instances of TreeListBox
    const currentQuery = search !== undefined ? search : searchQuery
    // Skip search if this was triggered by a checkbox interaction
    if (isCheckboxInteraction.current) {
      return
    }
    // Use a more stable way to detect data changes
    const searchDependenciesChanged =
      currentQuery !== searchDataDependencies.current.query ||
      data.length !== searchDataDependencies.current.data.length
    // Trigger search on query changes, data length changes, or initial data load
    if (searchDependenciesChanged) {
      // Set searching state to show loader
      if (currentQuery && currentQuery.length >= 3) {
        setIsSearching(true)
      }
      // Update dependencies
      searchDataDependencies.current = {
        data,
        query: currentQuery,
      }
      // Call debouncedSearch for query changes
      debouncedSearchRefactored({
        query: currentQuery,
        identifierKeys: identifierKeys,
        setFilteredItems: (items) => {
          setFilteredItems(items)
          // Once we have results, hide the loader
          setIsSearching(false)
        },
        nestedConfigData: data,
        toggleExpand: onToggleExpand,
      })
    } else {
      // Reset searching state if only other dependencies changed
      setIsSearching(false)
    }
  }, [search, data, searchQuery, identifierKeys, onToggleExpand])

  const emptyStateContent = (emptyStateProps: EmptyStateProps) => {
    return (
      <div className={tableStyles.listLoadingWrapper}>
        <EmptyState {...emptyStateProps} />
      </div>
    )
  }

  return (
    <>
      {/** TODO: Remove SearchBar and isSearchable prop once search prop is implemented at all instances of TreeListBox */}
      {search !== undefined ? (
        <></>
      ) : (
        isSearchable && (
          <SearchBar
            debounce={300}
            onChange={(value) => {
              // Reset checkbox interaction flag when search changes
              isCheckboxInteraction.current = false
              setSearchQuery(value)
            }}
            value={searchQuery}
          />
        )
      )}
      <StickyTableContainer
        hasData={hasData}
        loading={isLoading}
        customHeight={customHeight}
        customWidth={customWidth}
        qaTestId={qaTestId}
      >
        <StickyTable borderWidth={0}>
          <Row className={`${tableStyles.stickyTableHeader}`}>
            {tableConfig.map((column, index) => (
              <Cell
                key={index}
                className={`${index === 0 ? styles.primaryColumn : ''}`}
              >
                <UnsortedColumn label={column.label} />
              </Cell>
            ))}
            <Cell>
              {/* empty cell for the expand/collapse */}
              <UnsortedColumn label={''} />
            </Cell>
          </Row>
          {isLoading || isSearching ? (
            <div className={tableStyles.listLoadingWrapper}>
              <ListLoading longList={true} />
            </div>
          ) : (search !== undefined ? search : searchQuery) &&
            filteredItems?.length === 0 ? (
            emptyStateContent({
              primaryText: c('noResultsFound'),
              secondaryText: c('updateSearchField'),
            })
          ) : hasData ? (
            <CheckboxList
              items={
                (search !== undefined ? search : searchQuery)
                  ? filteredItems
                  : data
              }
              onClick={clickHandler}
              expandedItems={expandedItems}
              onToggleExpand={onToggleExpand}
              getStateForId={getStateForId}
              tableConfig={tableConfig}
              idKey={idKey}
              parentKey={parentKey}
              displayKey={displayKey}
              pathKey='pathId'
            />
          ) : (
            emptyStateContent({ ...noDataTextProps })
          )}
        </StickyTable>
      </StickyTableContainer>
    </>
  )
}

export default TreeListBox
