/**
 * ImageGallery 图片画廊组件
 * 支持手势滑动切换图片、双指放大、点击关闭
 * 使用 expo-image，原生支持 GIF/WebP 动图
 */

import React, { useState, useCallback, useEffect, useMemo, useRef } from 'react';
import {
  Modal,
  View,
  StyleSheet,
  Dimensions,
  TouchableOpacity,
  Text,
  StatusBar,
  Alert,
} from 'react-native';
import { Image as ExpoImage } from 'expo-image';
import {
  Gesture,
  GestureDetector,
  GestureHandlerRootView,
} from 'react-native-gesture-handler';
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  runOnJS,
  withTiming,
} from 'react-native-reanimated';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import * as MediaLibrary from 'expo-media-library';
import { File, Paths } from 'expo-file-system';
import { spacing, borderRadius, fontSizes } from '../../theme';

const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window');

// 图片项类型
export interface GalleryImageItem {
  id: string;
  url: string;
  thumbnailUrl?: string;
  width?: number;
  height?: number;
  description?: string;
}

// 组件 Props
export interface ImageGalleryProps {
  /** 是否可见 */
  visible: boolean;
  /** 图片列表 */
  images: GalleryImageItem[];
  /** 初始索引 */
  initialIndex: number;
  /** 关闭回调 */
  onClose: () => void;
  /** 索引变化回调 */
  onIndexChange?: (index: number) => void;
  /** 是否显示指示器 */
  showIndicator?: boolean;
  /** 是否允许保存图片 */
  enableSave?: boolean;
  /** 保存图片成功回调 */
  onSave?: (url: string) => void;
  /** 背景透明度 */
  backgroundOpacity?: number;
}

/**
 * 图片画廊主组件
 */
export const ImageGallery: React.FC<ImageGalleryProps> = ({
  visible,
  images,
  initialIndex,
  onClose,
  onIndexChange,
  showIndicator = true,
  enableSave = false,
  onSave,
  backgroundOpacity = 1,
}) => {
  const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const isClosingRef = useRef(false);
  const currentIndexRef = useRef(initialIndex);
  const pendingSwipeDirectionRef = useRef<-1 | 1 | null>(null);
  const [currentIndex, setCurrentIndex] = useState(initialIndex);
  currentIndexRef.current = currentIndex;
  const [showControls, setShowControls] = useState(true);
  const [error, setError] = useState(false);
  const [saving, setSaving] = useState(false);
  const [saveToast, setSaveToast] = useState<'success' | 'error' | null>(null);

  const insets = useSafeAreaInsets();

  // 缩放相关状态
  const scale = useSharedValue(1);
  const savedScale = useSharedValue(1);
  const translateX = useSharedValue(0);
  const translateY = useSharedValue(0);
  const savedTranslateX = useSharedValue(0);
  const savedTranslateY = useSharedValue(0);

  const validImages = useMemo(() => {
    return images.filter(img => img.url);
  }, [images]);

  const currentImage = useMemo(() => {
    if (currentIndex < 0 || currentIndex >= validImages.length) {
      return null;
    }
    return validImages[currentIndex];
  }, [validImages, currentIndex]);

  // 重置缩放状态
  const resetZoom = useCallback(() => {
    scale.value = withTiming(1, { duration: 200 });
    savedScale.value = 1;
    translateX.value = withTiming(0, { duration: 200 });
    translateY.value = withTiming(0, { duration: 200 });
    savedTranslateX.value = 0;
    savedTranslateY.value = 0;
  }, [scale, savedScale, translateX, translateY, savedTranslateX, savedTranslateY]);

  // 打开/关闭时重置状态
  useEffect(() => {
    if (visible) {
      setCurrentIndex(initialIndex);
      setShowControls(true);
      setError(false);
      resetZoom();
      StatusBar.setHidden(true, 'fade');
    } else {
      StatusBar.setHidden(false, 'fade');
    }
  }, [visible, initialIndex, resetZoom]);

  useEffect(() => {
    if (visible) {
      isClosingRef.current = false;
    }
  }, [visible]);

  useEffect(() => {
    return () => {
      if (closeTimerRef.current) {
        clearTimeout(closeTimerRef.current);
      }
    };
  }, []);

  // 图片变化时重置缩放（加载态在 updateIndex / 打开弹窗时同步设置，避免晚一帧仍显示上一张）
  useEffect(() => {
    resetZoom();
  }, [currentImage?.id, resetZoom]);

  const updateIndex = useCallback(
    (newIndex: number) => {
      const clampedIndex = Math.max(0, Math.min(validImages.length - 1, newIndex));
      if (clampedIndex === currentIndexRef.current) {
        return;
      }
      setError(false);
      setCurrentIndex(clampedIndex);
      onIndexChange?.(clampedIndex);
    },
    [validImages.length, onIndexChange]
  );

  const updateIndexFromSwipe = useCallback(
    (newIndex: number, direction: -1 | 1) => {
      pendingSwipeDirectionRef.current = direction;
      updateIndex(newIndex);
    },
    [updateIndex]
  );

  const toggleControls = useCallback(() => {
    setShowControls(prev => !prev);
  }, []);

  const requestClose = useCallback(() => {
    if (isClosingRef.current) {
      return;
    }

    isClosingRef.current = true;
    // 延迟一个短时间窗口，避免关闭同一触摸触发到底层组件
    closeTimerRef.current = setTimeout(() => {
      onClose();
    }, 120);
  }, [onClose]);

  // 显示短暂提示
  const showToast = useCallback((type: 'success' | 'error') => {
    setSaveToast(type);
    setTimeout(() => setSaveToast(null), 2500);
  }, []);

  // 保存图片到本地相册
  const handleSaveImage = useCallback(async () => {
    if (!currentImage || saving) return;

    const { status } = await MediaLibrary.requestPermissionsAsync();
    if (status !== 'granted') {
      Alert.alert('无法保存', '请在系统设置中允许访问相册权限后重试。');
      return;
    }

    setSaving(true);
    try {
      const urlPath = currentImage.url.split('?')[0];
      const ext = urlPath.split('.').pop()?.toLowerCase() ?? 'jpg';
      const allowedExts = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
      const fileExt = allowedExts.includes(ext) ? ext : 'jpg';

      const fileName = `carrot_${Date.now()}.${fileExt}`;
      const destination = new File(Paths.cache, fileName);

      // File.downloadFileAsync 是新版 expo-file-system/next 的静态方法
      const downloaded = await File.downloadFileAsync(currentImage.url, destination);

      await MediaLibrary.saveToLibraryAsync(downloaded.uri);

      // 清理缓存文件
      downloaded.delete();

      onSave?.(currentImage.url);
      showToast('success');
    } catch (err) {
      console.error('[ImageGallery] 保存图片失败:', err);
      showToast('error');
    } finally {
      setSaving(false);
    }
  }, [currentImage, saving, onSave, showToast]);

  // 双指缩放手势
  const pinchGesture = Gesture.Pinch()
    .onUpdate((e) => {
      const newScale = savedScale.value * e.scale;
      // 限制缩放范围
      scale.value = Math.max(0.5, Math.min(newScale, 4));
    })
    .onEnd(() => {
      // 如果缩放小于1，回弹到1
      if (scale.value < 1) {
        scale.value = withTiming(1, { duration: 200 });
        savedScale.value = 1;
        translateX.value = withTiming(0, { duration: 200 });
        translateY.value = withTiming(0, { duration: 200 });
        savedTranslateX.value = 0;
        savedTranslateY.value = 0;
      } else {
        savedScale.value = scale.value;
      }
    });

  // 滑动切换图片相关状态
  const swipeTranslateX = useSharedValue(0);

  useEffect(() => {
    pendingSwipeDirectionRef.current = null;
    swipeTranslateX.value = 0;
  }, [currentIndex, swipeTranslateX]);

  const switchWithDirection = useCallback(
    (targetIndex: number, direction: -1 | 1) => {
      updateIndexFromSwipe(targetIndex, direction);
    },
    [updateIndexFromSwipe]
  );

  const goToPrev = useCallback(() => {
    if (currentIndex > 0) {
      switchWithDirection(currentIndex - 1, 1);
    }
  }, [currentIndex, switchWithDirection]);

  const goToNext = useCallback(() => {
    if (currentIndex < validImages.length - 1) {
      switchWithDirection(currentIndex + 1, -1);
    }
  }, [currentIndex, validImages.length, switchWithDirection]);

  // 统一的滑动手势：放大时拖动，未放大时切换图片
  const panGesture = Gesture.Pan()
    .activeOffsetX([-10, 10])  // 水平方向需要移动10pt才激活，避免与点击冲突
    .activeOffsetY([-10, 10])  // 垂直方向也需要一定偏移才激活
    .onBegin(() => {
      swipeTranslateX.value = 0;
    })
    .onUpdate((e) => {
      if (scale.value > 1) {
        // 放大状态下：拖动图片
        translateX.value = savedTranslateX.value + e.translationX;
        translateY.value = savedTranslateY.value + e.translationY;
      }
    })
    .onEnd((e) => {
      if (scale.value > 1) {
        // 放大状态下：保存拖动位置
        savedTranslateX.value = translateX.value;
        savedTranslateY.value = translateY.value;
      } else if (validImages.length > 1) {
        // 未放大状态下：判断是否切换图片
        const threshold = SCREEN_WIDTH * 0.2;
        const velocity = e.velocityX;

        const shouldGoNext = e.translationX < -threshold || velocity < -500;
        const shouldGoPrev = e.translationX > threshold || velocity > 500;

        if (shouldGoNext && currentIndex < validImages.length - 1) {
          // 向左滑动，显示下一张
          runOnJS(updateIndexFromSwipe)(currentIndex + 1, -1);
        } else if (shouldGoPrev && currentIndex > 0) {
          // 向右滑动，显示上一张
          runOnJS(updateIndexFromSwipe)(currentIndex - 1, 1);
        }
      }
    });

  // 点击手势（关闭 gallery）
  const tapGesture = Gesture.Tap()
    .numberOfTaps(1)
    .maxDistance(10)
    .onEnd(() => {
      runOnJS(requestClose)();
    });

  // 组合手势：
  // - pinchGesture 和 (panGesture / tapGesture) 可以同时识别
  // - panGesture 和 tapGesture 互斥（Race）：短按是点击，长按/滑动是拖动
  const composedGesture = Gesture.Simultaneous(
    pinchGesture,
    Gesture.Race(panGesture, tapGesture)
  );

  // 动画样式
  const animatedStyle = useAnimatedStyle(() => ({
    transform: [
      { translateX: translateX.value + swipeTranslateX.value },
      { translateY: translateY.value },
      { scale: scale.value },
    ] as const,
  }));

  if (!visible || validImages.length === 0) {
    return null;
  }

  return (
    <Modal
      visible={visible}
      transparent
      animationType="fade"
      onRequestClose={requestClose}
      statusBarTranslucent
    >
      <GestureHandlerRootView style={styles.root}>
        <View style={[styles.container, { backgroundColor: `rgba(0, 0, 0, ${backgroundOpacity})` }]}>
          {/* 顶部控制栏 */}
          {showControls && (
            <View style={[styles.header, { paddingTop: insets.top + spacing.md }]}>
              <TouchableOpacity style={styles.closeButton} onPress={requestClose}>
                <MaterialCommunityIcons name="close" size={24} color="#FFF" />
              </TouchableOpacity>

              <View style={styles.headerCenter}>
                <Text style={styles.pageIndicator}>
                  {currentIndex + 1} / {validImages.length}
                </Text>
              </View>

              {enableSave && (
                <TouchableOpacity
                  style={styles.saveButton}
                  onPress={handleSaveImage}
                  disabled={saving}
                >
                  {saving ? (
                    <MaterialCommunityIcons name="loading" size={24} color="#FFF" />
                  ) : (
                    <MaterialCommunityIcons name="download" size={24} color="#FFF" />
                  )}
                </TouchableOpacity>
              )}
            </View>
          )}

          {/* 图片显示区域 */}
          <GestureDetector gesture={composedGesture}>
            <View style={styles.imageContainer}>
              {error && (
                <View style={styles.errorContainer}>
                  <MaterialCommunityIcons name="image-off" size={48} color="#999" />
                  <Text style={styles.errorText}>加载失败</Text>
                </View>
              )}

              {currentImage && (
                <Animated.View style={[styles.imageWrapper, animatedStyle]}>
                  <ExpoImage
                    source={{ uri: currentImage.url }}
                    style={styles.image}
                    contentFit="contain"
                    cachePolicy="disk"
                    priority="high"
                    recyclingKey={currentImage.url}
                    transition={null}
                    allowDownscaling
                    onLoad={() => {
                      setError(false);
                    }}
                    onError={() => {
                      setError(true);
                    }}
                  />
                </Animated.View>
              )}
            </View>
          </GestureDetector>

          {/* 左右切换按钮 */}
          {showControls && validImages.length > 1 && (
            <>
              {currentIndex > 0 && (
                <TouchableOpacity
                  style={[styles.navButton, styles.navButtonLeft]}
                  onPress={goToPrev}
                  activeOpacity={0.7}
                >
                  <MaterialCommunityIcons name="chevron-left" size={36} color="#FFF" />
                </TouchableOpacity>
              )}

              {currentIndex < validImages.length - 1 && (
                <TouchableOpacity
                  style={[styles.navButton, styles.navButtonRight]}
                  onPress={goToNext}
                  activeOpacity={0.7}
                >
                  <MaterialCommunityIcons name="chevron-right" size={36} color="#FFF" />
                </TouchableOpacity>
              )}
            </>
          )}

          {/* 底部指示器 */}
          {showControls && showIndicator && validImages.length > 1 && (
            <View style={[styles.footer, { paddingBottom: insets.bottom + spacing.lg }]}>
              <View style={styles.dotsContainer}>
                {validImages.map((_, index) => (
                  <View
                    key={index}
                    style={[
                      styles.dot,
                      index === currentIndex && styles.activeDot,
                    ]}
                  />
                ))}
              </View>
            </View>
          )}

          {/* 保存结果 Toast */}
          {saveToast !== null && (
            <View style={[styles.toast, saveToast === 'success' ? styles.toastSuccess : styles.toastError]}>
              <MaterialCommunityIcons
                name={saveToast === 'success' ? 'check-circle-outline' : 'alert-circle-outline'}
                size={18}
                color="#FFF"
              />
              <Text style={styles.toastText}>
                {saveToast === 'success' ? '已保存到相册' : '保存失败，请重试'}
              </Text>
            </View>
          )}
        </View>
      </GestureHandlerRootView>
    </Modal>
  );
};

const styles = StyleSheet.create({
  root: {
    flex: 1,
  },
  container: {
    flex: 1,
    backgroundColor: '#000',
  },
  header: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    paddingHorizontal: spacing.md,
    paddingBottom: spacing.md,
    backgroundColor: 'rgba(0, 0, 0, 0.3)',
    zIndex: 10,
  },
  closeButton: {
    width: 40,
    height: 40,
    borderRadius: borderRadius.full,
    backgroundColor: 'rgba(255, 255, 255, 0.2)',
    justifyContent: 'center',
    alignItems: 'center',
  },
  headerCenter: {
    flex: 1,
    alignItems: 'center',
  },
  pageIndicator: {
    color: '#FFF',
    fontSize: fontSizes.md,
    fontWeight: '500',
  },
  saveButton: {
    width: 40,
    height: 40,
    borderRadius: borderRadius.full,
    backgroundColor: 'rgba(255, 255, 255, 0.2)',
    justifyContent: 'center',
    alignItems: 'center',
  },
  imageContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  imageWrapper: {
    width: SCREEN_WIDTH,
    height: SCREEN_HEIGHT,
    justifyContent: 'center',
    alignItems: 'center',
  },
  image: {
    width: SCREEN_WIDTH,
    height: SCREEN_HEIGHT * 0.8,
  },
  errorContainer: {
    ...StyleSheet.absoluteFillObject,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#000',
  },
  errorText: {
    color: '#999',
    fontSize: fontSizes.md,
    marginTop: spacing.sm,
  },
  navButton: {
    position: 'absolute',
    top: '50%',
    marginTop: -25,
    width: 50,
    height: 50,
    borderRadius: 25,
    backgroundColor: 'rgba(0, 0, 0, 0.4)',
    justifyContent: 'center',
    alignItems: 'center',
    zIndex: 10,
  },
  navButtonLeft: {
    left: spacing.sm,
  },
  navButtonRight: {
    right: spacing.sm,
  },
  footer: {
    position: 'absolute',
    bottom: 0,
    left: 0,
    right: 0,
    paddingVertical: spacing.lg,
    backgroundColor: 'rgba(0, 0, 0, 0.3)',
  },
  dotsContainer: {
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    gap: 8,
  },
  dot: {
    width: 8,
    height: 8,
    borderRadius: 4,
    backgroundColor: 'rgba(255, 255, 255, 0.4)',
  },
  activeDot: {
    width: 20,
    borderRadius: 4,
    backgroundColor: '#FFF',
  },
  toast: {
    position: 'absolute',
    bottom: 100,
    alignSelf: 'center',
    flexDirection: 'row',
    alignItems: 'center',
    gap: 6,
    paddingHorizontal: spacing.lg,
    paddingVertical: spacing.sm,
    borderRadius: borderRadius.full,
  },
  toastSuccess: {
    backgroundColor: 'rgba(34, 197, 94, 0.9)',
  },
  toastError: {
    backgroundColor: 'rgba(239, 68, 68, 0.9)',
  },
  toastText: {
    color: '#FFF',
    fontSize: fontSizes.sm,
    fontWeight: '500',
  },
});

export default ImageGallery;
