/**
 * S4. Search — MAPMAP-NAV-UI-SPEC.md.
 *
 * The search pill expands into this full sheet. Debouncing (≥250ms) and the
 * actual `mapmapNav.search()` call happen upstream (see App.tsx's
 * SearchContainer) — this component is purely a function of its props:
 * recents when the query is empty, live results/loading/no-results states
 * once it isn't.
 */
import React, { useMemo } from "react";
import {
  ActivityIndicator,
  FlatList,
  Keyboard,
  Pressable,
  StyleSheet,
  Text,
  TextInput,
  View,
} from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import Svg, { Circle, Line, Path } from "react-native-svg";
import { Chip, ListRow } from "../../components";
import { minTouchTarget, radius, spacing, theme, typeScale } from "../../theme";
import { useTerritory } from "../../state/territory";
import type { SavedPlace } from "../../state/saved";
import type { SearchResult, Units } from "../../state/types";
import { formatDistance } from "../mapChrome";

export type SearchSheetProps = {
  query: string;
  onQueryChange: (query: string) => void;
  results: SearchResult[];
  recents: SearchResult[];
  isSearching: boolean;
  onSelectResult: (result: SearchResult) => void;
  onClearRecents: () => void;
  onCancel: () => void;
  units: Units;
  /** Category quick-search chip tapped; defaults to `onQueryChange` so
   * tapping "Food" drives the same search as typing "food". */
  onCategoryPress?: (term: string) => void;
  /** Saved Home place, if the user has set one. */
  home?: SavedPlace;
  /** Saved Work place, if the user has set one. */
  work?: SavedPlace;
  /** Saved favourites (excludes Home/Work), most-recently-added first. */
  favourites?: SavedPlace[];
  /** "Set home"/"Set work" tapped when that slot is empty; defaults to a
   * no-op so App.tsx can wire it up after Saved Places lands. */
  onSetSaved?: (kind: "home" | "work") => void;
  /** Remove ("×") tapped on a saved entry; defaults to a no-op. */
  onRemoveSaved?: (id: string) => void;
};

type CategoryOption = { label: string; term: string };

const CATEGORY_OPTIONS: CategoryOption[] = [
  { label: "Petrol", term: "petrol" },
  { label: "Food", term: "food" },
  { label: "Coffee", term: "coffee" },
  { label: "Parking", term: "parking" },
  { label: "Hotels", term: "hotels" },
  { label: "ATM", term: "atm" },
];

const TERRITORY_NAMES: Record<string, string> = {
  uk: "United Kingdom",
  ireland: "Ireland",
};

function territoryDisplayName(territoryId: string | null): string {
  if (!territoryId) return "your offline territory";
  return TERRITORY_NAMES[territoryId] ?? territoryId.toUpperCase();
}

function resultKey(result: SearchResult, index: number): string {
  return `${result.name}-${result.position.latitude}-${result.position.longitude}-${index}`;
}

function SearchIcon(): React.JSX.Element {
  return (
    <Svg width={18} height={18} viewBox="0 0 24 24">
      <Circle cx={10.5} cy={10.5} r={6.5} stroke={theme.textSecondary} strokeWidth={2} fill="none" />
      <Line x1={15.5} y1={15.5} x2={21} y2={21} stroke={theme.textSecondary} strokeWidth={2} strokeLinecap="round" />
    </Svg>
  );
}

function ClearIcon(): React.JSX.Element {
  return (
    <Svg width={16} height={16} viewBox="0 0 24 24">
      <Line x1={5} y1={5} x2={19} y2={19} stroke={theme.textSecondary} strokeWidth={2.4} strokeLinecap="round" />
      <Line x1={19} y1={5} x2={5} y2={19} stroke={theme.textSecondary} strokeWidth={2.4} strokeLinecap="round" />
    </Svg>
  );
}

function PinLeading(): React.JSX.Element {
  return (
    <Svg width={20} height={20} viewBox="0 0 24 24">
      <Path
        d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7Zm0 9.5A2.5 2.5 0 1 1 12 6.5a2.5 2.5 0 0 1 0 5Z"
        fill={theme.textSecondary}
      />
    </Svg>
  );
}

function HomeIcon({ tone }: { tone: "set" | "unset" }): React.JSX.Element {
  const color = tone === "set" ? theme.signal : theme.textSecondary;
  return (
    <Svg width={20} height={20} viewBox="0 0 24 24">
      <Path
        d="M12 3 3 10.5V21h6v-6h6v6h6V10.5L12 3Z"
        fill={color}
      />
    </Svg>
  );
}

function WorkIcon({ tone }: { tone: "set" | "unset" }): React.JSX.Element {
  const color = tone === "set" ? theme.signal : theme.textSecondary;
  return (
    <Svg width={20} height={20} viewBox="0 0 24 24">
      <Path
        d="M9 4a2 2 0 0 0-2 2v1H4.5A1.5 1.5 0 0 0 3 8.5v9A1.5 1.5 0 0 0 4.5 19h15a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 19.5 7H17V6a2 2 0 0 0-2-2H9Zm0 3V6h6v1H9Zm-1.5 6.5h9v1.5h-9v-1.5Z"
        fill={color}
      />
    </Svg>
  );
}

export function SearchSheet({
  query,
  onQueryChange,
  results,
  recents,
  isSearching,
  onSelectResult,
  onClearRecents,
  onCancel,
  units,
  onCategoryPress,
  home,
  work,
  favourites = [],
  onSetSaved = () => {},
  onRemoveSaved = () => {},
}: SearchSheetProps): React.JSX.Element {
  const insets = useSafeAreaInsets();
  const { activeTerritoryId } = useTerritory();
  const isQueryEmpty = query.trim().length === 0;
  const territoryName = useMemo(
    () => territoryDisplayName(activeTerritoryId),
    [activeTerritoryId]
  );
  const handleCategoryPress = onCategoryPress ?? onQueryChange;

  // Selecting a result navigates away from search — drop the keyboard first
  // so it doesn't linger over the place card / map during the transition.
  const handleSelect = (result: SearchResult) => {
    Keyboard.dismiss();
    onSelectResult(result);
  };

  const renderResultRow = (result: SearchResult, index: number, isRecent: boolean) => (
    <ListRow
      key={resultKey(result, index)}
      title={result.name}
      subtitle={result.address || undefined}
      leading={<PinLeading />}
      trailing={
        typeof result.distanceMeters === "number" ? (
          <Text style={styles.distanceText}>{formatDistance(result.distanceMeters, units)}</Text>
        ) : undefined
      }
      onPress={() => handleSelect(result)}
      testID={`${isRecent ? "recent" : "result"}-row-${index}`}
    />
  );

  const renderHomeWorkRow = (kind: "home" | "work") => {
    const place = kind === "home" ? home : work;
    return (
      <ListRow
        key={kind}
        title={place ? place.label : kind === "home" ? "Set home" : "Set work"}
        subtitle={place ? place.address || undefined : `Add your ${kind} address`}
        leading={
          kind === "home" ? (
            <HomeIcon tone={place ? "set" : "unset"} />
          ) : (
            <WorkIcon tone={place ? "set" : "unset"} />
          )
        }
        onPress={() => (place ? handleSelect(place) : onSetSaved(kind))}
        testID={`saved-${kind}-row`}
      />
    );
  };

  const renderFavouriteRow = (place: SavedPlace, index: number) => (
    <ListRow
      key={place.id}
      title={place.label}
      subtitle={place.address || undefined}
      leading={<PinLeading />}
      trailing={
        <Pressable
          onPress={() => onRemoveSaved(place.id)}
          hitSlop={8}
          accessibilityRole="button"
          accessibilityLabel={`Remove ${place.label} from saved`}
        >
          <ClearIcon />
        </Pressable>
      }
      onPress={() => handleSelect(place)}
      testID={`favourite-row-${index}`}
    />
  );

  return (
    <View style={styles.container} testID="search-sheet">
      <View style={[styles.searchBar, { paddingTop: insets.top + spacing[3] }]}>
        <View style={styles.inputWrap}>
          <SearchIcon />
          <TextInput
            value={query}
            onChangeText={onQueryChange}
            placeholder="Search here"
            placeholderTextColor={theme.textSecondary}
            style={styles.input}
            autoFocus
            returnKeyType="search"
            clearButtonMode="never"
            autoCorrect={false}
            testID="search-input"
          />
          {query.length > 0 && (
            <Pressable
              onPress={() => onQueryChange("")}
              hitSlop={8}
              accessibilityLabel="Clear search"
              style={styles.clearButton}
            >
              <ClearIcon />
            </Pressable>
          )}
        </View>
        <Pressable
          onPress={onCancel}
          hitSlop={8}
          style={styles.cancelButton}
          accessibilityRole="button"
        >
          <Text style={styles.cancelText}>Cancel</Text>
        </Pressable>
      </View>

      {isQueryEmpty ? (
        <View style={styles.body}>
          <FlatList
            horizontal
            data={CATEGORY_OPTIONS}
            keyExtractor={(item) => item.term}
            showsHorizontalScrollIndicator={false}
            style={styles.categoryRow}
            contentContainerStyle={styles.categoryRowContent}
            keyboardShouldPersistTaps="handled"
            renderItem={({ item }) => (
              <Chip
                label={item.label}
                tone="neutral"
                onPress={() => handleCategoryPress(item.term)}
                testID={`category-chip-${item.term}`}
              />
            )}
          />
          <View style={styles.sectionHeader}>
            <Text style={styles.sectionTitle}>Saved</Text>
          </View>
          <View style={styles.savedSection}>
            {renderHomeWorkRow("home")}
            {renderHomeWorkRow("work")}
            {favourites.map((place, index) => renderFavouriteRow(place, index))}
          </View>
          <View style={styles.sectionHeader}>
            <Text style={styles.sectionTitle}>Recent</Text>
            {recents.length > 0 && (
              <Pressable onPress={onClearRecents} hitSlop={8}>
                <Text style={styles.clearRecentsText}>Clear</Text>
              </Pressable>
            )}
          </View>
          {recents.length === 0 ? (
            <View style={styles.emptyState}>
              <Text style={styles.emptyTitle}>No recent searches yet</Text>
              <Text style={styles.emptySubtitle}>
                Places you search for will appear here.
              </Text>
            </View>
          ) : (
            <FlatList
              data={recents}
              keyExtractor={resultKey}
              renderItem={({ item, index }) => renderResultRow(item, index, true)}
              keyboardShouldPersistTaps="handled"
            />
          )}
        </View>
      ) : (
        <View style={styles.body}>
          {isSearching ? (
            <View style={styles.centeredState}>
              <ActivityIndicator color={theme.signal} />
              <Text style={styles.searchingText}>Searching…</Text>
            </View>
          ) : results.length === 0 ? (
            <View style={styles.emptyState}>
              <Text style={styles.emptyTitle}>No places found in {territoryName}</Text>
              <Text style={styles.emptySubtitle}>
                Search is offline and scoped to your installed territory.
              </Text>
            </View>
          ) : (
            <FlatList
              data={results}
              keyExtractor={resultKey}
              renderItem={({ item, index }) => renderResultRow(item, index, false)}
              keyboardShouldPersistTaps="handled"
            />
          )}
        </View>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: theme.surface,
  },
  searchBar: {
    flexDirection: "row",
    alignItems: "center",
    paddingHorizontal: spacing[4],
    paddingBottom: spacing[3],
    gap: spacing[3],
    borderBottomWidth: 1,
    borderBottomColor: theme.border,
  },
  inputWrap: {
    flex: 1,
    flexDirection: "row",
    alignItems: "center",
    minHeight: minTouchTarget,
    backgroundColor: theme.surfaceAlt,
    borderRadius: radius.pill,
    paddingHorizontal: spacing[3],
    gap: spacing[2],
  },
  input: {
    flex: 1,
    fontSize: typeScale.body.fontSize,
    color: theme.textPrimary,
    paddingVertical: 0,
  },
  clearButton: {
    padding: spacing[1],
  },
  cancelButton: {
    minHeight: minTouchTarget,
    justifyContent: "center",
  },
  cancelText: {
    fontSize: typeScale.label.fontSize,
    fontWeight: typeScale.label.fontWeight,
    color: theme.signal,
  },
  body: {
    flex: 1,
  },
  categoryRow: {
    flexGrow: 0,
    paddingTop: spacing[4],
  },
  categoryRowContent: {
    paddingHorizontal: spacing[4],
    gap: spacing[2],
  },
  savedSection: {
    flexGrow: 0,
  },
  sectionHeader: {
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "space-between",
    paddingHorizontal: spacing[4],
    paddingTop: spacing[4],
    paddingBottom: spacing[2],
  },
  sectionTitle: {
    fontSize: typeScale.label.fontSize,
    fontWeight: typeScale.label.fontWeight,
    color: theme.textSecondary,
    textTransform: "uppercase",
  },
  clearRecentsText: {
    fontSize: typeScale.label.fontSize,
    fontWeight: typeScale.label.fontWeight,
    color: theme.signal,
  },
  distanceText: {
    fontSize: typeScale.caption.fontSize,
    color: theme.textSecondary,
  },
  centeredState: {
    alignItems: "center",
    justifyContent: "center",
    paddingTop: spacing[12],
    gap: spacing[3],
  },
  searchingText: {
    fontSize: typeScale.body.fontSize,
    color: theme.textSecondary,
  },
  emptyState: {
    alignItems: "center",
    paddingHorizontal: spacing[8],
    paddingTop: spacing[12],
    gap: spacing[2],
  },
  emptyTitle: {
    fontSize: typeScale.body.fontSize,
    fontWeight: "600",
    color: theme.textPrimary,
    textAlign: "center",
  },
  emptySubtitle: {
    fontSize: typeScale.caption.fontSize,
    color: theme.textSecondary,
    textAlign: "center",
  },
});
