import { DeleteOutlined, LockOutlined } from '@mui/icons-material'
import {
  Box,
  Divider,
  IconButton,
  Paper,
  Popover,
  SvgIcon,
  TextField,
  type SxProps,
  type Theme,
} from '@mui/material'
import {
  useRef,
  useState,
  type JSX,
  type KeyboardEvent,
  type MouseEvent,
  type ReactNode,
} from 'react'
import { Tooltip } from '../tooltip/tooltip'
import { SpatialMaskIcon, TextAaIcon } from './icons'
import type { LassoGeometryToolbarUIProps } from './types'

const ICON_SIZE = 18

const containerSx = {
  display: 'flex',
  flexDirection: 'row',
  alignItems: 'center',
  width: 'fit-content',
  gap: ({ spacing }) => spacing(0.5),
  p: ({ spacing }) => spacing(0.5),
  borderRadius: ({ spacing }) => spacing(0.5),
  backgroundColor: ({ palette }) => palette.background.paper,
} satisfies SxProps<Theme>

const baseButtonSx = {
  p: ({ spacing }) => spacing(0.375),
  borderRadius: ({ spacing }) => spacing(0.5),
  '.MuiTouchRipple-ripple .MuiTouchRipple-child': {
    borderRadius: ({ spacing }) => spacing(0.5),
  },
} satisfies SxProps<Theme>

/** Active = Figma toggle "selected" treatment (primary tint); inactive = gray. */
const toggleButtonSx = (active: boolean): SxProps<Theme> => ({
  ...baseButtonSx,
  color: ({ palette }) =>
    active ? palette.primary.main : palette.text.secondary,
  backgroundColor: active ? 'rgba(3, 111, 226, 0.08)' : 'transparent',
  '&:hover': {
    backgroundColor: ({ palette }) =>
      active ? 'rgba(3, 111, 226, 0.12)' : palette.action.hover,
  },
})

/**
 * Contextual toolbar for a single lasso geometry: toggle mask/draw, rename,
 * lock, and delete. Purely presentational — position it over the map and wire
 * the callbacks to the lasso store (see `LassoTools.GeometryToolbar` in
 * `@carto/ps-react-maps`).
 *
 * Each button keeps a fixed icon and toggles an active highlight: the mask
 * button is active when `type === 'mask'`, the lock button is active when
 * `locked`. When `locked`, every action but the lock toggle is disabled.
 */
export function LassoGeometryToolbarUI({
  type,
  label,
  locked = false,
  onToggleType,
  onRename,
  onToggleLock,
  onDelete,
  labels,
  PaperProps: { sx, ...PaperProps } = {},
}: LassoGeometryToolbarUIProps): JSX.Element {
  const paperRef = useRef<HTMLDivElement>(null)
  // Guards `onRename` to once per rename session — the Popover `onClose` and the
  // TextField `onBlur` can both fire for a single close (and Enter blurs on unmount).
  const committedRef = useRef(false)
  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null)
  const [barWidth, setBarWidth] = useState<number>()
  const [draft, setDraft] = useState(label)

  const renaming = Boolean(anchorEl)

  const toggleTypeLabel =
    type === 'mask'
      ? (labels?.toggleType?.draw ?? 'Switch to drawing')
      : (labels?.toggleType?.mask ?? 'Switch to mask')
  const renameLabel = labels?.rename ?? 'Rename'
  const renameInputLabel = labels?.renameInput ?? renameLabel
  const lockLabel = locked
    ? (labels?.lock?.unlock ?? 'Unlock')
    : (labels?.lock?.lock ?? 'Lock')
  const deleteLabel = labels?.delete ?? 'Delete'

  const openRename = () => {
    committedRef.current = false
    setDraft(label)
    setBarWidth(paperRef.current?.clientWidth)
    setAnchorEl(paperRef.current)
  }

  const commitRename = () => {
    if (!committedRef.current) {
      committedRef.current = true
      const next = draft.trim()
      if (next && next !== label) {
        onRename(next)
      }
    }
    setAnchorEl(null)
  }

  // Escape discards the edit: mark the session done so the unmount blur / onClose
  // don't fire `onRename`.
  const cancelRename = () => {
    committedRef.current = true
    setAnchorEl(null)
  }

  const handleRenameKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
    if (event.key === 'Enter') {
      event.preventDefault()
      commitRename()
    }
    if (event.key === 'Escape') {
      event.preventDefault()
      cancelRename()
    }
  }

  return (
    <Paper
      ref={paperRef}
      elevation={6}
      sx={{ ...containerSx, ...sx }}
      {...PaperProps}
    >
      <ToolbarButton
        label={toggleTypeLabel}
        active={type === 'mask'}
        pressed={type === 'mask'}
        disabled={locked}
        onClick={() => onToggleType(type === 'mask' ? 'draw' : 'mask')}
        icon={
          <SvgIcon
            component={SpatialMaskIcon}
            inheritViewBox
            sx={{ fontSize: ICON_SIZE }}
          />
        }
      />

      <Divider orientation='vertical' flexItem />

      <ToolbarButton
        label={renameLabel}
        active={renaming}
        disabled={locked}
        onClick={openRename}
        icon={
          <SvgIcon
            component={TextAaIcon}
            inheritViewBox
            sx={{ fontSize: ICON_SIZE }}
          />
        }
      />

      <Divider orientation='vertical' flexItem />

      <ToolbarButton
        label={lockLabel}
        active={locked}
        pressed={locked}
        onClick={() => onToggleLock(!locked)}
        icon={<LockOutlined sx={{ fontSize: ICON_SIZE }} />}
      />

      <Divider orientation='vertical' flexItem />

      <ToolbarButton
        label={deleteLabel}
        disabled={locked}
        onClick={onDelete}
        icon={<DeleteOutlined sx={{ fontSize: ICON_SIZE }} />}
        color='error'
      />

      <Popover
        open={renaming}
        anchorEl={anchorEl}
        onClose={commitRename}
        anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
        transformOrigin={{ vertical: 'top', horizontal: 'left' }}
        slotProps={{
          paper: {
            sx: { width: barWidth, minWidth: 180 },
          },
        }}
      >
        <Box sx={{ p: 1 }}>
          <TextField
            inputRef={(node: HTMLInputElement | null) => node?.focus()}
            fullWidth
            label={renameInputLabel}
            size='small'
            variant='outlined'
            value={draft}
            onChange={(e) => setDraft(e.target.value)}
            onKeyDown={handleRenameKeyDown}
            onBlur={commitRename}
          />
        </Box>
      </Popover>
    </Paper>
  )
}

function ToolbarButton({
  label,
  icon,
  active = false,
  pressed,
  disabled = false,
  color,
  onClick,
}: {
  label: string
  icon: ReactNode
  active?: boolean
  /** When set, exposes `aria-pressed` so the button reads as a toggle. */
  pressed?: boolean
  disabled?: boolean
  color?: 'error'
  onClick: (event: MouseEvent<HTMLButtonElement>) => void
}): ReactNode {
  return (
    <Tooltip title={label} placement='top'>
      <span>
        <IconButton
          aria-label={label}
          aria-pressed={pressed}
          disabled={disabled}
          color={color}
          onClick={onClick}
          sx={color ? baseButtonSx : toggleButtonSx(active)}
        >
          {icon}
        </IconButton>
      </span>
    </Tooltip>
  )
}
