/**
 * SlideToConfirm — pure RN, no RNGH, no Reanimated.
 * PanResponder on handle + Animated(useNativeDriver:false).
 *
 * Fix history:
 * - v1: stale closure fix — disabledRef + onConfirmRef
 * - v2: trackWidth=0 snap bug — trackWidthRef+State, startPos/currentPos refs,
 *       eliminated _value/_offset private API, layout guard on gesture start
 */
import { 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_MARGIN = 3;
const THRESHOLD     = 0.80;

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

  const confirmed   = useRef(false);
  const translateX  = useRef(new Animated.Value(0)).current;

  // Explicit position tracking — avoids private _value/_offset API
  const startPos    = useRef(0);   // handle position when gesture starts
  const currentPos  = useRef(0);   // handle position during/after gesture

  // ── Live refs: break stale closures ──────────────────────────────────────
  const disabledRef  = useRef(disabled);
  disabledRef.current = disabled;
  const onConfirmRef = useRef(onConfirm);
  onConfirmRef.current = onConfirm;

  const panResponder = useRef(
    PanResponder.create({
      // Block gestures until layout has been measured
      onStartShouldSetPanResponder: () =>
        !disabledRef.current && trackWidthRef.current > 0,
      // Horizontal-dominance — prevents ScrollView stealing on iOS
      onMoveShouldSetPanResponder: (_, gs) =>
        !disabledRef.current &&
        trackWidthRef.current > 0 &&
        Math.abs(gs.dx) > Math.abs(gs.dy) * 2,

      onPanResponderGrant: () => {
        confirmed.current = false;
        // Stop any running spring before starting a new drag
        translateX.stopAnimation();
        startPos.current = currentPos.current;
      },

      onPanResponderMove: (_, gs) => {
        const maxX = trackWidthRef.current - HANDLE_SIZE - HANDLE_MARGIN * 2;
        if (maxX <= 0) return; // safety — layout not ready

        const raw     = startPos.current + gs.dx;
        const clamped = Math.min(Math.max(raw, 0), maxX);
        currentPos.current = clamped;
        translateX.setValue(clamped);

        if (!confirmed.current && clamped / maxX >= THRESHOLD) {
          confirmed.current = true;
          Animated.spring(translateX, {
            toValue: maxX,
            useNativeDriver: false,
            damping: 18,
            stiffness: 220,
          }).start(({ finished }) => {
            if (finished) currentPos.current = maxX;
          });
          onConfirmRef.current();
        }
      },

      onPanResponderRelease: () => {
        if (!confirmed.current) {
          currentPos.current = 0;
          Animated.spring(translateX, {
            toValue: 0,
            useNativeDriver: false,
            damping: 18,
            stiffness: 220,
          }).start(({ finished }) => {
            if (finished) currentPos.current = 0;
          });
        }
      },

      onPanResponderTerminate: () => {
        if (!confirmed.current) {
          currentPos.current = 0;
          Animated.spring(translateX, {
            toValue: 0,
            useNativeDriver: false,
          }).start(({ finished }) => {
            if (finished) currentPos.current = 0;
          });
        }
      },
    })
  ).current;

  const maxXForOpacity = Math.max(trackWidthState - HANDLE_SIZE - HANDLE_MARGIN * 2, 1);
  const labelOpacity = translateX.interpolate({
    inputRange:  [0, maxXForOpacity * 0.6],
    outputRange: [1, 0],
    extrapolate: 'clamp',
  });

  return (
    <View
      style={[
        styles.track,
        disabled && styles.trackDisabled,
        color && !disabled ? { backgroundColor: color } : undefined,
        style,
      ]}
      onLayout={e => {
        const w = e.nativeEvent.layout.width;
        trackWidthRef.current = w;   // PanResponder reads this
        setTrackWidthState(w);       // triggers re-render for labelOpacity
      }}
    >
      <Animated.View
        style={[StyleSheet.absoluteFill, styles.labelWrap, { opacity: labelOpacity }]}
        pointerEvents="none"
      >
        <Text style={styles.label}>{label}</Text>
      </Animated.View>

      <Animated.View
        style={[
          styles.handle,
          disabled && styles.handleDisabled,
          { transform: [{ translateX }] },
        ]}
        {...panResponder.panHandlers}
        collapsable={false}
      >
        <Text style={styles.arrow}>›</Text>
      </Animated.View>
    </View>
  );
}

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