/**
 * S9. Settings (pushed screen) — MAPMAP-NAV-UI-SPEC.md.
 *
 * Grouped-list styling throughout (iOS "Settings.app" pattern): rows live
 * inside rounded Card sections with hairline dividers, never as bare
 * switches loose on white. Reached by the gear icon in the S3 search pill
 * and pushed via react-navigation, which supplies the header bar/title —
 * this screen renders body content only.
 *
 * Theme (Light/Dark/System) is spec'd as "if dark shipped; else hide" — the
 * app only ships light today (AppSettings has no themeMode field; see
 * src/theme.ts's module doc), so that row is intentionally omitted here.
 */
import React, { useMemo, useRef } from "react";
import {
  LayoutChangeEvent,
  PanResponder,
  PanResponderGestureState,
  ScrollView,
  StyleSheet,
  Switch,
  Text,
  View,
} from "react-native";
import Svg, { Path } from "react-native-svg";
import { Card, ListRow, SegmentedControl } from "../../components";
import { radius, spacing, theme, typeScale } from "../../theme";
import type { AppSettings, Units } from "../../state/types";

export type SettingsScreenProps = {
  settings: AppSettings;
  onUpdateSettings: (patch: Partial<AppSettings>) => void;
  onTestVoice: () => void;
  onNavigateTerritories: () => void;
  onNavigateAbout: () => void;
  /** "online" = hosted tiles, no download; "offline" = installed territory. */
  mapSource: "online" | "offline";
  onMapSourceChange: (source: "online" | "offline") => void;
};

const UNIT_OPTIONS: Array<{ value: Units; label: string }> = [
  { value: "km", label: "Kilometres" },
  { value: "mi", label: "Miles" },
];

const THEME_OPTIONS: Array<{ value: "light" | "dark"; label: string }> = [
  { value: "light", label: "Light" },
  { value: "dark", label: "Dark" },
];

const MAP_SOURCE_OPTIONS: Array<{ value: "online" | "offline"; label: string }> = [
  { value: "online", label: "Online" },
  { value: "offline", label: "Offline" },
];

export function SettingsScreen({
  settings,
  onUpdateSettings,
  onTestVoice,
  onNavigateTerritories,
  onNavigateAbout,
  mapSource,
  onMapSourceChange,
}: SettingsScreenProps): React.JSX.Element {
  return (
    <ScrollView
      style={styles.container}
      contentContainerStyle={styles.content}
      testID="settings-screen"
    >
      <Section title="Voice guidance">
        <ListRow
          title="Voice guidance"
          trailing={
            <Switch
              value={!settings.voiceMuted}
              onValueChange={(value) => onUpdateSettings({ voiceMuted: !value })}
              trackColor={{ false: theme.border, true: theme.signal }}
              thumbColor={theme.surface}
              ios_backgroundColor={theme.border}
              accessibilityLabel="Voice guidance"
              testID="settings-voice-toggle"
            />
          }
        />
        <View style={styles.volumeRow}>
          <Text style={styles.rowTitle}>Volume</Text>
          <VolumeSlider
            value={settings.volume}
            disabled={settings.voiceMuted}
            onChange={(volume) => onUpdateSettings({ volume })}
          />
        </View>
        <ListRow
          title="Test voice"
          subtitle="Play a sample instruction"
          onPress={onTestVoice}
          trailing={<PlayGlyph />}
          testID="settings-test-voice"
        />
      </Section>

      <Section title="Navigation">
        <View style={styles.unitsRow}>
          <Text style={styles.rowTitle}>Map source</Text>
          <SegmentedControl
            options={MAP_SOURCE_OPTIONS}
            value={mapSource}
            onChange={onMapSourceChange}
            testID="settings-map-source"
          />
        </View>
        <View style={styles.unitsRow}>
          <Text style={styles.rowTitle}>Distance units</Text>
          <SegmentedControl
            options={UNIT_OPTIONS}
            value={settings.units}
            onChange={(units) => onUpdateSettings({ units })}
            testID="settings-units"
          />
        </View>
        <ListRow
          title="Keep screen awake"
          subtitle="Prevents the screen sleeping during navigation"
          trailing={
            <Switch
              value={settings.keepAwake}
              onValueChange={(keepAwake) => onUpdateSettings({ keepAwake })}
              trackColor={{ false: theme.border, true: theme.signal }}
              thumbColor={theme.surface}
              ios_backgroundColor={theme.border}
              accessibilityLabel="Keep screen awake"
              testID="settings-keep-awake-toggle"
            />
          }
        />
      </Section>

      <Section title="Map">
        <View style={styles.unitsRow}>
          <Text style={styles.rowTitle}>Theme</Text>
          <SegmentedControl
            options={THEME_OPTIONS}
            value={settings.mapTheme}
            onChange={(mapTheme) => onUpdateSettings({ mapTheme })}
            testID="settings-map-theme"
          />
        </View>
        <ListRow
          title="3D buildings"
          subtitle="Extruded buildings when you tilt in"
          trailing={
            <Switch
              value={settings.show3dBuildings}
              onValueChange={(show3dBuildings) => onUpdateSettings({ show3dBuildings })}
              trackColor={{ false: theme.border, true: theme.signal }}
              thumbColor={theme.surface}
              ios_backgroundColor={theme.border}
              accessibilityLabel="3D buildings"
              testID="settings-3d-toggle"
            />
          }
        />
        <ListRow
          title="Points of interest"
          subtitle="Shops, stations and landmarks on the map"
          trailing={
            <Switch
              value={settings.showPois}
              onValueChange={(showPois) => onUpdateSettings({ showPois })}
              trackColor={{ false: theme.border, true: theme.signal }}
              thumbColor={theme.surface}
              ios_backgroundColor={theme.border}
              accessibilityLabel="Points of interest"
              testID="settings-pois-toggle"
            />
          }
        />
      </Section>

      <Section title="More">
        <ListRow
          title="Territories"
          subtitle="Manage installed offline maps"
          onPress={onNavigateTerritories}
          trailing={<ChevronRight />}
          testID="settings-territories-row"
        />
        <ListRow
          title="About"
          subtitle="Version, licences and privacy"
          onPress={onNavigateAbout}
          trailing={<ChevronRight />}
          testID="settings-about-row"
        />
      </Section>
    </ScrollView>
  );
}

/* ================= internal building blocks ================= */

function Section({
  title,
  children,
}: {
  title: string;
  children: React.ReactNode;
}): React.JSX.Element {
  const items = React.Children.toArray(children);
  return (
    <View>
      <Text style={styles.sectionTitle}>{title}</Text>
      <Card padded={false} style={styles.sectionCard}>
        {items.map((child, index) => (
          <React.Fragment key={index}>
            {child}
            {index < items.length - 1 ? <View style={styles.divider} /> : null}
          </React.Fragment>
        ))}
      </Card>
    </View>
  );
}

const clamp = (value: number, min: number, max: number): number =>
  Math.max(min, Math.min(max, value));

function VolumeSlider({
  value,
  onChange,
  disabled = false,
}: {
  value: number;
  onChange: (value: number) => void;
  disabled?: boolean;
}): React.JSX.Element {
  const trackWidthRef = useRef(0);
  // Absolute (page) X of the track's left edge, captured on touch-down —
  // onPanResponderMove's gestureState.moveX is page-relative, so this pair
  // sidesteps the well-known iOS locationX drift once a drag leaves the
  // view's original bounds.
  const trackPageXRef = useRef(0);

  const handleLayout = (event: LayoutChangeEvent): void => {
    trackWidthRef.current = event.nativeEvent.layout.width;
  };

  const setFromAbsoluteX = (pageX: number): void => {
    const width = trackWidthRef.current;
    if (width <= 0) return;
    onChange(clamp((pageX - trackPageXRef.current) / width, 0, 1));
  };

  const panResponder = useMemo(
    () =>
      PanResponder.create({
        onStartShouldSetPanResponder: () => !disabled,
        onMoveShouldSetPanResponder: () => !disabled,
        onPanResponderGrant: (event) => {
          trackPageXRef.current =
            event.nativeEvent.pageX - event.nativeEvent.locationX;
          setFromAbsoluteX(event.nativeEvent.pageX);
        },
        onPanResponderMove: (_event, gesture: PanResponderGestureState) =>
          setFromAbsoluteX(gesture.moveX),
      }),
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [disabled, onChange]
  );

  const clamped = clamp(value, 0, 1);

  return (
    <View
      onLayout={handleLayout}
      style={[styles.sliderTrack, disabled && styles.sliderTrackDisabled]}
      {...(disabled ? {} : panResponder.panHandlers)}
      accessibilityRole="adjustable"
      accessibilityLabel="Voice volume"
      accessibilityValue={{ min: 0, max: 100, now: Math.round(clamped * 100) }}
      hitSlop={8}
      testID="settings-volume-slider"
    >
      <View style={styles.sliderFillTrack}>
        <View style={[styles.sliderFill, { width: `${clamped * 100}%` }]} />
      </View>
      <View
        style={[
          styles.sliderThumb,
          disabled && styles.sliderThumbDisabled,
          { left: `${clamped * 100}%`, marginLeft: -10 },
        ]}
      />
    </View>
  );
}

function PlayGlyph(): React.JSX.Element {
  return (
    <Svg width={16} height={16} viewBox="0 0 24 24" accessibilityLabel="Play">
      <Path d="M7 4 L20 12 L7 20 Z" fill={theme.signal} />
    </Svg>
  );
}

function ChevronRight(): React.JSX.Element {
  return (
    <Svg width={10} height={16} viewBox="0 0 10 16" accessibilityLabel="Open">
      <Path
        d="M1.5 1.5 L8 8 L1.5 14.5"
        stroke={theme.textSecondary}
        strokeWidth={2}
        strokeLinecap="round"
        strokeLinejoin="round"
        fill="none"
      />
    </Svg>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: theme.background,
  },
  content: {
    padding: spacing[4],
    gap: spacing[6],
    paddingBottom: spacing[10],
  },
  sectionTitle: {
    fontSize: typeScale.caption.fontSize,
    fontWeight: typeScale.label.fontWeight,
    color: theme.textSecondary,
    textTransform: "uppercase",
    letterSpacing: 0.5,
    marginBottom: spacing[2],
    marginLeft: spacing[1],
  },
  sectionCard: {
    overflow: "hidden",
  },
  divider: {
    height: StyleSheet.hairlineWidth,
    backgroundColor: theme.border,
    marginLeft: spacing[4],
  },
  rowTitle: {
    fontSize: typeScale.body.fontSize,
    fontWeight: "500",
    color: theme.textPrimary,
  },
  volumeRow: {
    paddingHorizontal: spacing[4],
    paddingVertical: spacing[3],
    gap: spacing[3],
  },
  unitsRow: {
    paddingHorizontal: spacing[4],
    paddingVertical: spacing[3],
    gap: spacing[3],
  },
  sliderTrack: {
    height: 24,
    justifyContent: "center",
  },
  sliderTrackDisabled: {
    opacity: 0.4,
  },
  sliderFillTrack: {
    height: 6,
    borderRadius: radius.pill,
    backgroundColor: theme.surfaceAlt,
    overflow: "hidden",
  },
  sliderFill: {
    height: "100%",
    borderRadius: radius.pill,
    backgroundColor: theme.signal,
  },
  sliderThumb: {
    position: "absolute",
    top: 2,
    width: 20,
    height: 20,
    borderRadius: radius.pill,
    backgroundColor: theme.surface,
    ...theme.shadow,
  },
  sliderThumbDisabled: {
    backgroundColor: theme.surfaceAlt,
  },
});
