/**
 * @ai-summary Autocomplete component for selecting gas stations
 * Integrates with saved stations and nearby search
 */

import React, { useState, useCallback, useMemo, useEffect } from 'react';
import {
  Autocomplete,
  TextField,
  Box,
  Typography,
  CircularProgress,
  InputAdornment
} from '@mui/material';
import {
  Bookmark as BookmarkIcon,
  LocationOn as LocationIcon
} from '@mui/icons-material';
import { useSavedStations } from '../../stations/hooks/useSavedStations';
import { useStationsSearch } from '../../stations/hooks/useStationsSearch';
import { Station, SavedStation, GeolocationCoordinates } from '../../stations/types/stations.types';
import {
  resolveSavedStationAddress,
  resolveSavedStationCoordinates,
  resolveSavedStationName,
  resolveSavedStationPlaceId
} from '../../stations/utils/savedStations';
import { LocationData } from '../types/fuel-logs.types';

interface StationPickerProps {
  /** Current location data value */
  value?: LocationData;
  /** Callback when station is selected */
  onChange: (value?: LocationData) => void;
  /** User's current location (optional) */
  userLocation?: GeolocationCoordinates | null;
  /** Placeholder text */
  placeholder?: string;
  /** Error message */
  error?: string;
}

interface StationOption {
  type: 'saved' | 'nearby' | 'manual';
  station?: Station | SavedStation;
  label: string;
  group: string;
}

/**
 * Format distance from meters to user-friendly string
 */
function formatDistance(meters: number): string {
  const miles = meters / 1609.34;
  if (miles < 0.1) return '< 0.1 mi';
  if (miles < 10) return `${miles.toFixed(1)} mi`;
  return `${Math.round(miles)} mi`;
}

/**
 * Check if station is saved
 */
function isSavedStation(station: Station | SavedStation): station is SavedStation {
  return 'userId' in station;
}

/**
 * StationPicker Component
 *
 * Autocomplete component that allows users to:
 * - Select from saved stations
 * - Search nearby stations (if location available)
 * - Enter manual text input
 *
 * Features:
 * - Grouped options (Saved / Nearby)
 * - Debounced search (300ms)
 * - Loading indicators
 * - Fallback to text input on API failure
 * - Distance display
 * - Bookmark icons for saved stations
 */
export const StationPicker: React.FC<StationPickerProps> = ({
  value,
  onChange,
  userLocation,
  placeholder = 'Station location (optional)',
  error
}) => {
  const [inputValue, setInputValue] = useState(value?.stationName || '');
  const [searchTrigger, setSearchTrigger] = useState(0);

  // Fetch saved stations
  const { data: savedStations, isPending: savedLoading } = useSavedStations();

  // Search mutation for nearby stations
  const { mutate: searchStations, data: nearbyStations, isPending: searchLoading } = useStationsSearch();

  // Debounced search effect
  useEffect(() => {
    if (!userLocation || !inputValue || inputValue.length < 2) {
      return;
    }

    const timer = setTimeout(() => {
      setSearchTrigger((prev) => prev + 1);
    }, 300);

    return () => clearTimeout(timer);
  }, [inputValue, userLocation]);

  // Execute search when trigger changes
  useEffect(() => {
    if (searchTrigger > 0 && userLocation) {
      searchStations({
        latitude: userLocation.latitude,
        longitude: userLocation.longitude,
        radius: 8000 // 5 miles in meters
      });
    }
  }, [searchTrigger, userLocation, searchStations]);

  // Build options list
  const options: StationOption[] = useMemo(() => {
    const opts: StationOption[] = [];

    // Add saved stations first
    if (savedStations && savedStations.length > 0) {
      savedStations.forEach((station) => {
        const placeId = resolveSavedStationPlaceId(station);
        if (!placeId) {
          return;
        }

        const normalizedStation =
          station.placeId === placeId ? station : { ...station, placeId };

        opts.push({
          type: 'saved',
          station: normalizedStation,
          label: resolveSavedStationName(normalizedStation),
          group: 'Saved Stations'
        });
      });
    }

    // Add nearby stations
    if (nearbyStations && nearbyStations.length > 0) {
      // Filter out stations already in saved list
      const savedPlaceIds = new Set(
        (savedStations || [])
          .map((station) => resolveSavedStationPlaceId(station))
          .filter((id): id is string => Boolean(id))
      );

      nearbyStations
        .filter((station) => !savedPlaceIds.has(station.placeId))
        .forEach((station) => {
          opts.push({
            type: 'nearby',
            station,
            label: station.name,
            group: 'Nearby Stations'
          });
        });
    }

    return opts;
  }, [savedStations, nearbyStations]);

  // Handle option selection
  const handleChange = useCallback(
    (_event: React.SyntheticEvent, newValue: StationOption | string | null) => {
      if (!newValue) {
        onChange(undefined);
        setInputValue('');
        return;
      }

      // Manual text input (freeSolo)
      if (typeof newValue === 'string') {
        onChange({
          stationName: newValue
        });
        setInputValue(newValue);
        return;
      }

      // Selected from options
      const { station } = newValue;
      if (station) {
        const saved = isSavedStation(station);
        const placeId = saved
          ? resolveSavedStationPlaceId(station) || station.placeId
          : station.placeId;
        const name = saved ? resolveSavedStationName(station) : station.name;
        const address = saved ? resolveSavedStationAddress(station) : station.address;

        let latitude = station.latitude;
        let longitude = station.longitude;

        if ((latitude === undefined || longitude === undefined) && saved) {
          const coords = resolveSavedStationCoordinates(station);
          if (coords) {
            latitude = coords.latitude;
            longitude = coords.longitude;
          }
        }

        onChange({
          stationName: name,
          address,
          googlePlaceId: placeId,
          coordinates:
            latitude !== undefined && longitude !== undefined
              ? {
                  latitude,
                  longitude
                }
              : undefined
        });
        setInputValue(name);
      }
    },
    [onChange]
  );

  // Handle input text change
  const handleInputChange = useCallback((_event: React.SyntheticEvent, newInputValue: string) => {
    setInputValue(newInputValue);
  }, []);

  // Custom option rendering
  const renderOption = useCallback(
    (props: React.HTMLAttributes<HTMLLIElement>, option: StationOption | string) => {
      // Handle manual text input option
      if (typeof option === 'string') {
        return (
          <li {...props}>
            <Typography variant="body2">{option}</Typography>
          </li>
        );
      }

      const { station, type } = option;
      if (!station) return null;

      const isSaved = isSavedStation(station);
      const displayName = isSaved && station.nickname ? station.nickname : station.name;
      const distance = station.distance ? formatDistance(station.distance) : null;

      return (
        <li {...props}>
          <Box display="flex" alignItems="center" width="100%" gap={1}>
            {type === 'saved' && (
              <BookmarkIcon fontSize="small" color="primary" />
            )}
            {type === 'nearby' && (
              <LocationIcon fontSize="small" color="action" />
            )}
            <Box flex={1} minWidth={0}>
              <Typography variant="body2" noWrap>
                {displayName}
              </Typography>
              <Typography variant="caption" color="text.secondary" noWrap>
                {distance && `${distance} • `}
                {station.address}
              </Typography>
            </Box>
          </Box>
        </li>
      );
    },
    []
  );

  // Group options by category
  const groupBy = useCallback((option: StationOption | string) => {
    if (typeof option === 'string') return '';
    return option.group;
  }, []);

  // Get option label
  const getOptionLabel = useCallback((option: StationOption | string) => {
    if (typeof option === 'string') return option;
    return option.label;
  }, []);

  // Loading state
  const isLoading = savedLoading || searchLoading;

  return (
    <Autocomplete
      freeSolo
      options={options}
      value={null} // Controlled by inputValue
      inputValue={inputValue}
      onChange={handleChange}
      onInputChange={handleInputChange}
      groupBy={groupBy}
      getOptionLabel={getOptionLabel}
      renderOption={renderOption}
      filterOptions={(opts) => opts} // Don't filter, we control options
      loading={isLoading}
      loadingText="Searching stations..."
      noOptionsText={
        userLocation
          ? 'No stations found. Type to enter manually.'
          : 'Enable location to search nearby stations.'
      }
      renderInput={(params) => (
        <TextField
          {...params}
          label="Location (optional)"
          placeholder={placeholder}
          error={!!error}
          helperText={error || (userLocation ? 'Search saved or nearby stations' : 'Type station name')}
          InputProps={{
            ...params.InputProps,
            endAdornment: (
              <>
                {isLoading && (
                  <InputAdornment position="end">
                    <CircularProgress size={20} />
                  </InputAdornment>
                )}
                {params.InputProps.endAdornment}
              </>
            )
          }}
        />
      )}
      sx={(theme) => ({
        '& .MuiAutocomplete-groupLabel': {
          fontWeight: 600,
          backgroundColor: 'grey.100',
          ...theme.applyStyles('dark', {
            backgroundColor: '#4C4E4D',
          }),
          fontSize: '0.75rem',
          textTransform: 'uppercase',
          letterSpacing: '0.5px'
        },
        '& .MuiAutocomplete-option': {
          minHeight: '44px', // Mobile touch target
          padding: '8px 16px'
        }
      })}
    />
  );
};
