import {
  Divider,
  Typography,
  SvgIcon,
  ToggleButton,
  Box,
  ToggleButtonGroup,
  Button,
} from '@mui/material'
import { useMemo, type JSX, type MouseEvent, type ReactNode } from 'react'
import { styles } from './styles'
import type {
  LassoToolsComponentProps,
  LassoToolsInlineComponentProps,
} from './types'
import { LASSO_TOOLS_LABELS } from './const'
import type { PickDeep } from 'type-fest'
import type { LassoToolsModes } from '../types'
import deepmerge from 'deepmerge'
import { LassoToolsUIChip } from './chip'
import { Tooltip } from '../tooltip/tooltip'

const EMPTY_VALUES: LassoToolsInlineComponentProps['values'] = []
const EMPTY_BOX_PROPS: NonNullable<LassoToolsInlineComponentProps['BoxProps']> =
  {}

/**
 * Provides an inline layout variant of the lasso tools interface with toggle button groups for mode selection and inline chip management for spatial filters.
 *
 * @example
 * ```tsx
 * <LassoToolsInlineUI
 *   enabled={enabled}
 *   values={spatialFilters}
 *   modes={modes}
 *   modesMapping={modesMapping}
 *   modeSelected={modeSelected}
 *   onChangeMode={setModeSelected}
 *   onChipToggle={handleChipToggle}
 *   onDelete={handleDelete}
 * />
 * ```
 */
export function LassoToolsInlineUI({
  enabled,
  values = EMPTY_VALUES,
  chipProps,
  labels,
  modes,
  modesMapping,
  modeSelected,
  BoxProps: { sx, ...BoxProps } = EMPTY_BOX_PROPS,
  onChipToggle,
  onDelete,
  onChangeMode,
  onAllChipToggle,
  onAllDelete,
}: LassoToolsInlineComponentProps): JSX.Element {
  const data = useMemo(() => {
    return deepmerge(modes, modesMapping)
  }, [modes, modesMapping])

  const { edit, ..._modes } = data

  const handleDelete: LassoToolsComponentProps['onDelete'] = (valueId) => {
    return onDelete(valueId)
  }

  const handleClick = (
    evt: MouseEvent<HTMLElement>,
    mode: NonNullable<(typeof modes)[keyof typeof modes]>['value'],
  ) => {
    evt.preventDefault()
    onChangeMode?.(mode)
  }

  const modeExists = (modeSelected ?? '') in modes

  const mode = (
    modeExists ? modeSelected : Object.keys(data)[0]
  ) as keyof typeof data

  const modeSelectedValue = enabled ? data[mode] : null

  const modesValues = Object.values(_modes)

  return (
    <Box
      sx={{
        ...styles.container,
        ...sx,
      }}
      {...BoxProps}
      className='inline'
    >
      <ModeList data={modesValues} labels={labels?.options}>
        <ToggleButtonGroup
          value={modeSelectedValue?.value}
          exclusive
          className='inline'
          sx={styles.options.menu}
          onChange={handleClick}
        >
          <OptionsList labels={labels?.options} data={modesValues} />
          {!!edit && (
            <>
              <Divider orientation='vertical' />
              <OptionsList
                labels={labels?.options}
                data={[
                  {
                    ...edit,
                    disabled: !values.length,
                  },
                ]}
              />
            </>
          )}
        </ToggleButtonGroup>
      </ModeList>
      <Divider flexItem />
      <NoData hasValues={!!values.length} labels={labels?.noData} />
      {!!values.length && (
        <Box sx={styles.chip.container} className='inline'>
          {values.map((value) => (
            <LassoToolsUIChip
              key={value.id}
              value={value}
              labels={labels?.chip}
              chipProps={chipProps}
              onDelete={handleDelete}
              onChipToggle={onChipToggle}
            />
          ))}
        </Box>
      )}
      <Actions
        values={values}
        labels={labels?.actions}
        onAllChipToggle={onAllChipToggle}
        onAllDelete={onAllDelete}
      />
    </Box>
  )
}

function ModeList({
  data,
  labels,
  children,
}: {
  labels?: PickDeep<LassoToolsComponentProps['labels'], 'options'>['options']
  data: LassoToolsComponentProps['modes'][keyof LassoToolsModes][]
  children: ReactNode
}) {
  if (data.length <= 1) {
    return null
  }

  const modeTitle = labels?.mode?.title ?? LASSO_TOOLS_LABELS.options.mode.title

  return (
    <>
      <Typography
        variant='subtitle2'
        color='text.secondary'
        sx={styles.options.title}
        className='inline'
      >
        {modeTitle}
      </Typography>
      {children}
    </>
  )
}

function OptionsList({
  data,
  labels,
}: {
  labels?: PickDeep<LassoToolsComponentProps['labels'], 'options'>['options']
  data: (LassoToolsComponentProps['modes'] &
    LassoToolsComponentProps['modesMapping'])[keyof LassoToolsModes][]
}) {
  return data
    .filter((mode): mode is NonNullable<typeof mode> => Boolean(mode))
    .map((mode) => {
      const options =
        labels?.mode?.options ?? LASSO_TOOLS_LABELS.options.mode.options
      const label = options[mode.value]

      return (
        <Tooltip key={mode.value} title={label} placement='bottom'>
          <ToggleButton
            disabled={!!mode.disabled}
            value={mode.value}
            aria-label={mode.value}
          >
            <SvgIcon>{mode.icon}</SvgIcon>
          </ToggleButton>
        </Tooltip>
      )
    })
}

function NoData({
  hasValues,
  labels,
}: {
  hasValues: boolean
  labels: PickDeep<LassoToolsComponentProps['labels'], 'noData'>['noData']
}) {
  if (hasValues) {
    return null
  }

  const title = labels?.title ?? LASSO_TOOLS_LABELS.noData.title
  const description =
    labels?.description ?? LASSO_TOOLS_LABELS.noData.description

  return (
    <>
      <Typography variant='body1' color='textSecondary'>
        {title}
      </Typography>
      <Typography variant='body2' color='textSecondary'>
        {description}
      </Typography>
    </>
  )
}

function Actions({
  values,
  labels,
  onAllChipToggle,
  onAllDelete,
}: Pick<
  LassoToolsComponentProps,
  'values' | 'onAllChipToggle' | 'onAllDelete'
> & {
  labels?: PickDeep<LassoToolsComponentProps['labels'], 'actions'>['actions']
}) {
  if (values.length <= 1) {
    return null
  }

  const hasVisible = values.some((value) => value.visible)

  const toggleAllLabel = hasVisible
    ? (labels?.toggleAll?.active ?? LASSO_TOOLS_LABELS.actions.toggleAll.active)
    : (labels?.toggleAll?.inactive ??
      LASSO_TOOLS_LABELS.actions.toggleAll.inactive)

  const deleteAllLabel =
    labels?.deleteAll ?? LASSO_TOOLS_LABELS.actions.deleteAll

  return (
    <Box>
      <Button color='inherit' onClick={() => onAllChipToggle()}>
        {toggleAllLabel}
      </Button>
      <Button color='error' onClick={() => onAllDelete()}>
        {deleteAllLabel}
      </Button>
    </Box>
  )
}
