import { Box, Slider, TextField } from '@mui/material'
import { useState, useMemo, type FocusEvent, type KeyboardEvent } from 'react'
import { widgetStoreActions } from '../../stores/widget-store'
import { useWidgetSelector } from '../../stores/use-widget-selector'
import type { RangeItemProps, RangeWidgetState } from '../types'
import { styles } from '../style'

import { defaultFormatter } from '../../utils/formatter'

type EditingState = '' | 'min' | 'max'

/**
 * Renders a single range slider with editable min/max text inputs, reading its configuration from the widget store.
 */
export function RangeItem({ id, index }: RangeItemProps) {
  const {
    item,
    onChange,
    formatter: _formatter,
  } = useWidgetSelector(id, (w) => {
    const rw = w as RangeWidgetState | undefined
    return {
      item: rw?.data[index],
      onChange: rw?.onChange,
      formatter: rw?.formatter,
    }
  })
  const formatter = _formatter ?? defaultFormatter

  const currentValue = useMemo(
    () => (item ? (item.value ?? [item.min, item.max]) : [0, 0]),
    [item],
  )

  // Local state for input values - track if user is editing
  const [isEditing, setIsEditing] = useState<EditingState>('')

  if (!item) return null

  const handleSliderChange = (_: Event, newValue: number | number[]) => {
    if (Array.isArray(newValue)) {
      const [min, max] = newValue
      const data =
        widgetStoreActions.getWidget<RangeWidgetState>(id)?.data ?? []

      data[index] = {
        ...item,
        value: newValue,
      }

      widgetStoreActions.setWidget(id, {
        data,
      })

      onChange?.([min!, max!], index)
    }
  }

  const handleInputFocus = (e: FocusEvent<HTMLInputElement>) => {
    setIsEditing(e.target.name as EditingState)
  }

  const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = event.target

    let newValue: [number, number]
    if (name === 'min') {
      newValue = [
        Math.min(
          Math.max(item.min, parseFloat(value) || item.min),
          currentValue[1]!,
        ),
        currentValue[1] ?? 0,
      ]
    } else {
      newValue = [
        currentValue[0] ?? 0,
        Math.max(
          Math.min(item.max, parseFloat(value) || item.max),
          currentValue[0]!,
        ),
      ]
    }

    const data = widgetStoreActions.getWidget<RangeWidgetState>(id)?.data ?? []

    widgetStoreActions.setWidget(id, {
      data: data.map((d: RangeWidgetState['data'][number], i: number) =>
        i === index
          ? {
              ...d,
              value: newValue,
            }
          : d,
      ),
    })

    onChange?.([newValue[0], newValue[1]], index)
  }

  const handleInputBlur = (e: FocusEvent<HTMLInputElement>) => {
    setIsEditing('')
    handleInputChange(e)
  }

  const handleInputKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
    if (event.key === 'Enter') {
      handleInputBlur(event as unknown as FocusEvent<HTMLInputElement>)
      event.currentTarget.blur()
    }
  }

  return (
    <Box sx={styles.rangeItem}>
      <Box sx={styles.sliderContainer}>
        <Slider
          value={currentValue}
          onChange={handleSliderChange}
          valueLabelDisplay='auto'
          valueLabelFormat={formatter}
          min={item.min}
          max={item.max}
          step={item.step}
          marks={item.marks}
          disabled={item.disabled}
          sx={{
            ...styles.slider,
            ...(item.color && {
              color: item.color,
            }),
          }}
        />
      </Box>

      <Box sx={styles.inputsRow}>
        <Input
          key={`min-${currentValue[0]}`}
          isEditing={isEditing}
          name='min'
          value={currentValue[0] ?? 0}
          formatter={formatter}
          onFocus={handleInputFocus}
          onBlur={handleInputBlur}
          onKeyDown={handleInputKeyDown}
          disabled={item.disabled}
          inputProps={{
            'aria-label': 'Minimum value',
          }}
        />
        <Input
          key={`max-${currentValue[1]}`}
          isEditing={isEditing}
          name='max'
          value={currentValue[1] ?? 0}
          formatter={formatter}
          onFocus={handleInputFocus}
          onBlur={handleInputBlur}
          onKeyDown={handleInputKeyDown}
          disabled={item.disabled}
          inputProps={{
            'aria-label': 'Maximum value',
          }}
        />
      </Box>
    </Box>
  )
}

function Input({
  isEditing,
  name,
  disabled,
  value,
  formatter,
  onFocus: onFocus,
  onBlur: onBlur,
  onKeyDown: onKeyDown,
  inputProps,
}: {
  isEditing: EditingState
  name: 'min' | 'max'
  disabled?: boolean
  value: number
  formatter: (value: number) => string
  onFocus: (e: FocusEvent<HTMLInputElement>) => void
  onBlur: (e: FocusEvent<HTMLInputElement>) => void
  onKeyDown: (e: KeyboardEvent<HTMLInputElement>) => void
  inputProps?: React.InputHTMLAttributes<HTMLInputElement>
}) {
  const [currentValue, setCurrentValue] = useState<string>(String(value))

  // Compute display values when not editing
  const displayMinValue = useMemo(
    () => formatter(Number(currentValue)),
    [currentValue, formatter],
  )

  return (
    <TextField
      name={name}
      value={isEditing === name ? currentValue : displayMinValue}
      onChange={(e) => {
        setCurrentValue(e.target.value)
      }}
      onFocus={onFocus}
      onBlur={onBlur}
      onKeyDown={onKeyDown}
      disabled={disabled}
      size='small'
      sx={styles.input}
      inputProps={inputProps}
    />
  )
}
