import React from 'react';
import Autocomplete from '@mui/material/Autocomplete';
import TextField from '@mui/material/TextField';
import InputAdornment from '@mui/material/InputAdornment';
import LocationOnOutlinedIcon from '@mui/icons-material/LocationOnOutlined';
import SearchIcon from '@mui/icons-material/Search';
import type { SxProps, Theme } from '@mui/material/styles';
import { Chip } from '../../atoms/Chip';
import { IconButton } from '../../atoms/IconButton';

// ─── Types ──────────────────────────────────────────────────────────────────

/** Props for the FA LocationSearchInput molecule */
export interface LocationSearchInputProps {
  /** Committed location value. When non-empty, rendered as a chip inside
   *  the input; when empty, placeholder shows and the input accepts typing. */
  value: string;
  /** Fires whenever the committed value changes — on explicit commit (Enter
   *  or search button) with the new value, or on chip delete with ''. */
  onChange: (value: string) => void;
  /** Optional extra callback fired *only* on explicit commit (not on chip
   *  delete). Useful for triggering search side-effects beyond the value
   *  update (analytics, external fetch, etc.). */
  onCommit?: (value: string) => void;
  /** Placeholder text shown when no value is committed and no draft typed. */
  placeholder?: string;
  /** Accessible label for the input. */
  'aria-label'?: string;
  /** MUI sx prop — merged after the molecule's internal correctness CSS.
   *  Use this to style the outlined input's chrome (bgcolor, shadow, border,
   *  radius). Internal CSS targets `.MuiAutocomplete-inputRoot` whereas most
   *  chrome sx uses `.MuiOutlinedInput-root`, so collisions are avoided. */
  sx?: SxProps<Theme>;
}

// ─── Internal correctness CSS ───────────────────────────────────────────────

/**
 * Absolute-anchors the commit button (end adornment) to the right edge of
 * the input — stock MUI Autocomplete does this on `.MuiAutocomplete-endAdornment`,
 * but overriding `InputProps.endAdornment` puts our button inside a
 * `.MuiInputAdornment-positionEnd` that defaults to `position: static` and
 * would slide left as chips / draft text fill the input.
 *
 * `pr: 5` on the input root reserves the right-edge lane so input content
 * can't run under the button. Selectors use `.MuiAutocomplete-inputRoot`
 * (not `.MuiOutlinedInput-root`) so caller sx for chrome can sit alongside
 * these rules without colliding on the same key.
 */
const INTERNAL_SX = {
  '& .MuiAutocomplete-inputRoot': {
    position: 'relative',
    pr: 5,
  },
  '& .MuiAutocomplete-inputRoot .MuiInputAdornment-positionEnd': {
    position: 'absolute',
    right: 8,
    top: '50%',
    transform: 'translateY(-50%)',
    height: 'auto',
    maxHeight: 'none',
    m: 0,
  },
} as const;

// ─── Component ──────────────────────────────────────────────────────────────

/**
 * Location search input with committed-chip semantics.
 *
 * - **Typing produces a draft** (local state, not propagated).
 * - **Pressing Enter or the primary-filled magnifying-glass button commits**
 *   the draft: fires `onChange(draft)` and `onCommit?.(draft)`, clears the
 *   draft, renders the committed value as a chip inside the input.
 * - **Tapping the chip's X** clears the committed value (`onChange('')`).
 *
 * Capped to one chip at a time — if the user commits a new value while a
 * chip exists, the new value replaces it. This matches the product intent
 * (one active location per search) and keeps the UX obvious.
 *
 * The molecule owns the endAdornment absolute-anchoring + right-side
 * padding so the commit button never drifts as chips / draft fill the input.
 * Chrome (bgcolor, shadow, border, radius) is caller-controlled via `sx`.
 *
 * Originally extracted from ProvidersStep (D046) where the same pattern
 * lived inline in both the mobile-map floating strip and the desktop/mobile
 * sticky search bar.
 */
export const LocationSearchInput = React.forwardRef<HTMLDivElement, LocationSearchInputProps>(
  (
    {
      value,
      onChange,
      onCommit,
      placeholder = 'Search a town or suburb...',
      'aria-label': ariaLabel = 'Search location',
      sx,
    },
    ref,
  ) => {
    const [draft, setDraft] = React.useState('');

    const commit = (next: string) => {
      const trimmed = next.trim();
      if (!trimmed) return;
      onChange(trimmed);
      onCommit?.(trimmed);
      setDraft('');
    };

    return (
      <Autocomplete
        ref={ref}
        multiple
        freeSolo
        options={[]}
        forcePopupIcon={false}
        clearIcon={null}
        value={value.trim() ? [value.trim()] : []}
        inputValue={draft}
        onInputChange={(_, newDraft, reason) => {
          // Autocomplete fires a 'reset' input-change after a commit that
          // would echo the committed value back into our draft — ignore it.
          if (reason === 'reset') return;
          setDraft(newDraft);
        }}
        onChange={(_, newValue) => {
          if (newValue.length === 0) {
            // Chip deleted
            onChange('');
            return;
          }
          // Cap at 1: take the most-recent entry as the new committed value.
          const last = newValue[newValue.length - 1];
          if (typeof last === 'string') commit(last);
        }}
        renderTags={(val, getTagProps) =>
          val.map((option, index) => {
            const { key, ...chipProps } = getTagProps({ index });
            return (
              <Chip
                key={key}
                label={option}
                size="small"
                aria-label={`Current location: ${option}. Press delete to clear.`}
                {...chipProps}
              />
            );
          })
        }
        renderInput={(params) => (
          <TextField
            {...params}
            placeholder={value.trim() ? '' : placeholder}
            size="small"
            inputProps={{
              ...params.inputProps,
              'aria-label': ariaLabel,
            }}
            InputProps={{
              ...params.InputProps,
              startAdornment: (
                <>
                  <InputAdornment position="start" sx={{ ml: 0.5, mr: 0.5 }}>
                    <LocationOnOutlinedIcon sx={{ color: 'text.secondary', fontSize: 20 }} />
                  </InputAdornment>
                  {params.InputProps.startAdornment}
                </>
              ),
              endAdornment: (
                <InputAdornment position="end">
                  <IconButton
                    aria-label="Search"
                    onClick={() => commit(draft)}
                    sx={{
                      width: 28,
                      height: 28,
                      borderRadius: '50%',
                      bgcolor: 'primary.main',
                      color: 'primary.contrastText',
                      '&:hover': { bgcolor: 'primary.dark' },
                      '&:focus-visible': { outline: 'none' },
                    }}
                  >
                    <SearchIcon sx={{ fontSize: 16 }} />
                  </IconButton>
                </InputAdornment>
              ),
            }}
          />
        )}
        sx={[INTERNAL_SX, ...(Array.isArray(sx) ? sx : [sx])]}
      />
    );
  },
);

LocationSearchInput.displayName = 'LocationSearchInput';
export default LocationSearchInput;
