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

import Checkbox from '../Form/Checkbox'
import styles from './_treeListBox.module.scss'
import Button from '../Button/Button'
import Icon from '../Icons/Icon'
import ListLoading from '../Loaders/ListLoading'
import {
  type CheckboxListProps,
  CheckboxState,
} from '../Form/NestedCheckboxHelper'

const GroupScrollContainer: React.FC<{
  maxHeight: number | string
  hasMore: boolean
  isFetching: boolean
  fetchNextPage?: () => void
  children: React.ReactNode
}> = ({ maxHeight, hasMore, isFetching, fetchNextPage, children }) => {
  const sentinelRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    if (!isFetching && sentinelRef.current && hasMore) {
      const observer = new IntersectionObserver(
        (entries) => {
          entries.forEach((entry) => {
            if (entry.isIntersecting) {
              fetchNextPage?.()
            }
          })
        },
        { threshold: 0.3 },
      )
      observer.observe(sentinelRef.current)
      return () => observer.disconnect()
    }
  }, [hasMore, fetchNextPage, isFetching])

  return (
    <div style={{ maxHeight }} className='overflow-y-auto'>
      {children}
      {isFetching ? <ListLoading numberOfRows={3} noSlideInUp /> : null}
      {hasMore ? <div ref={sentinelRef} className='h-px' /> : null}
    </div>
  )
}

const CheckboxList: React.FC<CheckboxListProps> = ({
  items,
  getStateForId,
  idsToRender = [],
  onClick = () => {},
  expandedItems = {},
  onToggleExpand = () => {},
  indentLevel = 0,
  tableConfig,
  idKey,
  parentKey,
  displayKey,
  pathKey,
  className = '',
  groupScrollConfig,
}) => {
  const indentSize = 24

  if (!idsToRender.length) {
    const uniqueIds = new Set(
      items.filter((i) => !i[parentKey]).map((i) => i[idKey]),
    )
    idsToRender = Array.from(uniqueIds)
  }

  const getChildNodes = (parentId: string | number) => {
    const seenIds = new Set()
    const nodeItems = items.filter((i) => {
      return (
        i[parentKey] === parentId &&
        !seenIds.has(i[idKey]) &&
        seenIds.add(i[idKey])
      )
    })

    const groupCfg = groupScrollConfig?.groups?.[parentId]

    if (!nodeItems.length) {
      if (groupScrollConfig && groupCfg !== undefined && groupCfg.isFetching) {
        return (
          <div
            style={{ maxHeight: groupScrollConfig.maxHeight ?? '200px' }}
            className='overflow-y-auto'
          >
            <ListLoading numberOfRows={3} noSlideInUp />
          </div>
        )
      }
      return null
    }

    const childList = (
      <CheckboxList
        items={items}
        idsToRender={nodeItems.map((i) => i[idKey])}
        onClick={onClick}
        expandedItems={expandedItems}
        onToggleExpand={onToggleExpand}
        getStateForId={getStateForId}
        indentLevel={indentLevel + 1}
        tableConfig={tableConfig}
        idKey={idKey}
        parentKey={parentKey}
        displayKey={displayKey}
        pathKey={pathKey}
        className={className}
        groupScrollConfig={groupScrollConfig}
      />
    )

    if (groupScrollConfig && groupCfg !== undefined) {
      const maxHeight = groupScrollConfig.maxHeight ?? '200px'

      return (
        <GroupScrollContainer
          maxHeight={maxHeight}
          hasMore={groupCfg.hasMore ?? false}
          isFetching={groupCfg.isFetching ?? false}
          fetchNextPage={groupCfg.fetchNextPage}
        >
          {childList}
        </GroupScrollContainer>
      )
    }

    return childList
  }

  return (
    <>
      {idsToRender.map((id) => {
        const item = items.find((i) => i[idKey] === id)!
        const checkboxState = getStateForId(id)
        const isExpanded = expandedItems[id]
        const hasChildren = items.some((i) => i[parentKey] === id)

        return (
          <React.Fragment key={`${item[idKey]}-${item[pathKey]}`}>
            <Row className={className}>
              {tableConfig.map((column, index) => (
                <Cell
                  key={index}
                  style={{
                    ...tableConfig[index].style,
                    paddingLeft: index === 0 ? indentLevel * indentSize : 0, // Apply indentation only for the first column
                  }}
                  className={styles.treeCellContainer}
                >
                  {column.dataKey === displayKey ? (
                    <div className={styles.checkboxWrap}>
                      <Checkbox
                        label={''}
                        hideLabel
                        checked={checkboxState === CheckboxState.CHECKED}
                        callout={() => {
                          onClick(item[idKey])
                        }}
                        radioSize='12'
                        partialChecked={checkboxState === CheckboxState.PARTIAL}
                      />
                      {column.children(item, index)}
                    </div>
                  ) : null}
                  {column.dataKey !== displayKey
                    ? column.children(item, index)
                    : null}
                </Cell>
              ))}
              <Cell
                className={styles.treeCellContainer}
                // Override the base cell styles to meet the design requirements.
                style={{
                  padding: '4px 10px',
                }}
              >
                {hasChildren ? (
                  <Button as='unstyled' onClick={() => onToggleExpand(id)}>
                    <Icon
                      icon='caretDown'
                      className={`${styles.caret} ${styles.CaretIcon} ${
                        isExpanded ? styles.flipped : ''
                      }`}
                      color='purple'
                      iconSize='16px'
                    />
                  </Button>
                ) : null}
              </Cell>
            </Row>
            {isExpanded ? getChildNodes(item[idKey]) : null}
          </React.Fragment>
        )
      })}
    </>
  )
}

export default CheckboxList
