/**
 * SlideToConfirm — pure RN, no RNGH, no Reanimated.
 *
 * Key fix: Animated.event pipes gesture data directly to native thread
 * (no JS bridge delay) — this is what makes the handle actually track the finger.
 * useNativeDriver: true on all animations for 60fps smoothness.
 */
import { useEffect, useRef, useState } from 'react';
import {
  Animated,
  PanResponder,
  StyleSheet,
  Text,
  View,
  ViewStyle,
} from 'react-native';

interface Props {
  onConfirm: () => void;
  label?: string;
  disabled?: boolean;
  style?: ViewStyle;
  color?: string;
}

const HANDLE_SIZE    = 56;
const HANDLE_PADDING = 3;
const THRESHOLD      = 0.80;
const TIP_DISTANCE   = 28;
const TIP_DURATION   = 260;
const SNAP_DURATION  = 260;

export function SlideToConfirm({
  onConfirm,
  label = 'Slide to confirm',
  disabled = false,
  style,
  color,
}: Props) {
  // trackWidthRef — read inside PanResponder callbacks (no stale closure)
  // trackWidthState — triggers re-render so opacity interpolation updates
  const trackWidthRef = useRef(0);
  const [trackWidthState, setTrackWidthState] = useState(0);

  // pan drives all animation — useNativeDriver: true for all animations
  const pan = useRef(new Animated.Value(0)).current;

  const [isConfirmed, setIsConfirmed] = useState(false);
  const confirmedRef = useRef(false);

  // Live refs — break stale closures inside PanResponder
  const disabledRef  = useRef(disabled);
  disabledRef.current = disabled;
  const onConfirmRef = useRef(onConfirm);
  onConfirmRef.current = onConfirm;

  const getMaxX = () =>
    Math.max(trackWidthRef.current - HANDLE_SIZE - HANDLE_PADDING * 2, 1);

  const snapToEnd = () => {
    Animated.spring(pan, {
      toValue: getMaxX(),
      useNativeDriver: true,
      damping: 18,
      stiffness: 220,
    }).start(({ finished }) => {
      if (finished) {
        setIsConfirmed(true);
        onConfirmRef.current();
      }
    });
  };

  const snapBack = () => {
    Animated.timing(pan, {
      toValue: 0,
      duration: SNAP_DURATION,
      useNativeDriver: true,
    }).start(({ finished }) => {
      if (finished && !disabledRef.current) runTip();
    });
  };

  const runTip = () => {
    if (disabledRef.current) return;
    Animated.sequence([
      Animated.timing(pan, { toValue: TIP_DISTANCE, duration: TIP_DURATION, useNativeDriver: true }),
      Animated.timing(pan, { toValue: 0,            duration: TIP_DURATION, useNativeDriver: true }),
    ]).start();
  };

  useEffect(() => {
    const t = setTimeout(runTip, 700);
    return () => clearTimeout(t);
  }, []);

  const panResponder = useRef(
    PanResponder.create({
      // Claim gesture on touch start — ensures dx=0 at grant, no jump
      onStartShouldSetPanResponder: () =>
        !disabledRef.current && trackWidthRef.current > 0,
      // Also claim on move (horizontal dominant) as fallback
      onMoveShouldSetPanResponder: (_, gs) =>
        !disabledRef.current &&
        trackWidthRef.current > 0 &&
        Math.abs(gs.dx) > Math.abs(gs.dy),

      onPanResponderGrant: () => {
        confirmedRef.current = false;
        pan.stopAnimation();
        pan.setValue(0); // reset — Animated.event maps dx from 0
      },

      // Animated.event pipes dx directly to native thread — true 1:1 finger tracking
      onPanResponderMove: Animated.event(
        [null, { dx: pan }],
        { useNativeDriver: true }
      ),

      onPanResponderRelease: (_, gs) => {
        const maxX    = getMaxX();
        const clamped = Math.min(Math.max(gs.dx, 0), maxX);
        if (!confirmedRef.current && clamped / maxX >= THRESHOLD) {
          confirmedRef.current = true;
          snapToEnd();
        } else {
          snapBack();
        }
      },

      onPanResponderTerminate: () => {
        if (!confirmedRef.current) snapBack();
      },
    })
  ).current;

  const maxX = Math.max(trackWidthState - HANDLE_SIZE - HANDLE_PADDING * 2, 1);
  const labelOpacity = pan.interpolate({
    inputRange:  [0, maxX * 0.5],
    outputRange: [1, 0],
    extrapolate: 'clamp',
  });
  const checkOpacity = pan.interpolate({
    inputRange:  [maxX * 0.6, maxX],
    outputRange: [0, 1],
    extrapolate: 'clamp',
  });
  // Clamp translateX visually so handle doesn't overshoot track
  const clampedX = pan.interpolate({
    inputRange:  [0, maxX],
    outputRange: [0, maxX],
    extrapolate: 'clamp',
  });

  const trackColor = color && !disabled ? color : undefined;

  return (
    <View
      style={[
        styles.track,
        disabled && styles.trackDisabled,
        trackColor ? { backgroundColor: trackColor } : undefined,
        style,
      ]}
      onLayout={e => {
        const w = e.nativeEvent.layout.width;
        trackWidthRef.current = w;
        setTrackWidthState(w);
      }}
    >
      {/* "Slide to confirm" label — fades out as handle moves right */}
      <Animated.View
        style={[StyleSheet.absoluteFill, styles.center, { opacity: labelOpacity }]}
        pointerEvents="none"
      >
        <Text style={styles.label}>{label}</Text>
      </Animated.View>

      {/* "Confirmed ✓" label — fades in near end */}
      <Animated.View
        style={[StyleSheet.absoluteFill, styles.center, { opacity: checkOpacity }]}
        pointerEvents="none"
      >
        <Text style={[styles.label, styles.confirmedLabel]}>Confirmed ✓</Text>
      </Animated.View>

      {/* Sliding handle — driven by Animated.event (native thread) */}
      <Animated.View
        style={[
          styles.handle,
          disabled && styles.handleDisabled,
          { transform: [{ translateX: clampedX }] },
        ]}
        {...panResponder.panHandlers}
        collapsable={false}
      >
        {isConfirmed
          ? <Text style={[styles.icon, styles.checkIcon]}>✓</Text>
          : <Text style={styles.icon}>›</Text>
        }
      </Animated.View>
    </View>
  );
}

const styles = StyleSheet.create({
  track: {
    height: 60,
    backgroundColor: '#0E7490',
    borderRadius: 30,
    justifyContent: 'center',
    overflow: 'hidden',
  },
  trackDisabled: { backgroundColor: '#94A3B8' },
  center: { alignItems: 'center', justifyContent: 'center' },
  label: {
    color: 'rgba(255,255,255,0.85)',
    fontSize: 15,
    fontWeight: '600',
    letterSpacing: 0.3,
  },
  confirmedLabel: {
    color: '#fff',
    fontWeight: '700',
  },
  handle: {
    width: HANDLE_SIZE,
    height: HANDLE_SIZE,
    borderRadius: HANDLE_SIZE / 2,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
    marginLeft: HANDLE_PADDING,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.18,
    shadowRadius: 4,
    elevation: 4,
  },
  handleDisabled: { backgroundColor: '#E2E8F0' },
  icon: {
    fontSize: 28,
    color: '#0891B2',
    fontWeight: '800',
    lineHeight: 32,
  },
  checkIcon: {
    color: '#059669',
    fontSize: 24,
  },
});
