import React, { useEffect, useMemo, useState, useCallback, useRef } from 'react';
import { StyleSheet, ScrollView, Platform, Linking } from 'react-native';
import { Image as ExpoImage } from 'expo-image';
import { View, YStack } from 'tamagui';
import CustomText from '@/components/common/CustomText.jsx';
import { CustomSafeArea } from '@/components/common/CustomSafeArea';
import { CustomHeader } from '@/components/common/CustomHeader';
import { wp, sp } from '@/utils/ui/screenUtils';
import { useTranslation } from '@/node_modules/react-i18next';
import { useLocalSearchParams } from 'expo-router';
import { scheduleInfo } from '@/api/approve';
import { WebView } from 'react-native-webview';
import CustomImagePreview from '@/components/common/CustomImagePreview';
import { showError } from '@/utils/ui/toast';
import * as FileSystem from 'expo-file-system/legacy';
import * as Sharing from 'expo-sharing';
import { openBrowserAsync } from 'expo-web-browser';
import Animated from 'react-native-reanimated'
import useCrossFadeSkeleton from '@/hooks/approve/useCrossFadeSkeleton'

const AnnouncementDetailsScreen = () => {
  const { t } = useTranslation('common');
  const params = useLocalSearchParams();
  const uuid = useMemo(() => {
    const raw = Array.isArray(params?.uuid) ? params.uuid[0] : params?.uuid;
    return raw ? String(raw) : '';
  }, [params]);

  const [title, setTitle] = useState('');
  const [date, setDate] = useState('');
  const [contentHtml, setContentHtml] = useState('');
  const [attachments, setAttachments] = useState([]);
  const [webHeight, setWebHeight] = useState(wp(200));
  const lastHeightRef = useRef(webHeight);
  const { skeletonVisible, contentAnimatedStyle, skeletonAnimatedStyle, setLoading } = useCrossFadeSkeleton({ initiallyLoading: true });

  useEffect(() => {
    let mounted = true;
    const load = async () => {
      if (!uuid) return;
      try {
        const res = await scheduleInfo({ Uuid: uuid });
        const d = res?.data ?? {};
        if (!mounted) return;
        setTitle(String(d?.Title ?? ''));
        setDate(String(d?.CreatedAt ?? d?.CreatedTime ?? ''));
        setContentHtml(String(d?.Content ?? ''));
        setAttachments(Array.isArray(d?.Attachments) ? d.Attachments : []);
        setLoading(false);
      } catch (e) {}
    };
    load();
    return () => {
      mounted = false;
    };
  }, [uuid]);

  const injectedJS = useMemo(() => {
    // 计算文档高度并回传 RN，同时为所有 img 绑定点击事件，点击后回传 urls+index
    return `(() => {
      function sendHeight(){
        try {
          const height = Math.max(
            document.documentElement.scrollHeight,
            document.body.scrollHeight
          );
          window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({ type: 'height', height }));
        } catch(e) {}
      }

      function collectImageUrls(){
        try {
          const imgs = Array.prototype.slice.call(document.querySelectorAll('img'));
          return imgs.map(img => img.currentSrc || img.src || img.getAttribute('data-src') || '').filter(Boolean);
        } catch(e) { return []; }
      }

      function bindImages(){
        try {
          const imgs = Array.prototype.slice.call(document.querySelectorAll('img'));
          imgs.forEach((img) => {
            if (img && img.dataset && img.dataset.viewerBound) return;
            if (img && img.dataset) img.dataset.viewerBound = '1';
            img && img.addEventListener && img.addEventListener('click', function(e){
              try {
                e && e.preventDefault && e.preventDefault();
                e && e.stopPropagation && e.stopPropagation();
                const list = collectImageUrls();
                const clicked = this.currentSrc || this.src || this.getAttribute('data-src') || '';
                let index = list.indexOf(clicked);
                if (index < 0) index = 0;
                window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({ type: 'image_click', urls: list, index }));
              } catch(err) {}
            }, true);
          });
        } catch(e) {}
      }

      window.addEventListener('load', function(){
        sendHeight();
        bindImages();
      });

      const observer = new MutationObserver(() => setTimeout(() => { sendHeight(); bindImages(); }, 50));
      observer.observe(document.body, { childList: true, subtree: true, attributes: true });

      setTimeout(() => { sendHeight(); bindImages(); }, 100);
    })();`;
  }, []);

  const onMessage = useCallback((event) => {
    try {
      const data = JSON.parse(event?.nativeEvent?.data || '{}');
      if (data?.type === 'height' && Number(data?.height) > 0) {
        const next = Math.max(20, Number(data.height));
        // 避免频繁 setState：高度变化小于 2px 时忽略
        if (Math.abs(next - lastHeightRef.current) >= 2) {
          lastHeightRef.current = next;
          setWebHeight(next);
        }
      }
      if (data?.type === 'image_click') {
        const urls = Array.isArray(data?.urls) ? data.urls.filter(u => typeof u === 'string' && u) : [];
        if (urls.length) {
          const idx = Number.isFinite(data.index) ? Math.max(0, Math.min(urls.length - 1, Number(data.index))) : 0;
          CustomImagePreview.open(urls, { index: idx });
        }
      }
    } catch {}
  }, []);

  const htmlSource = useMemo(() => {
    const safe = contentHtml || '';
    const tpl = `<!DOCTYPE html><html><head><meta charset="utf-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
      <style>*{box-sizing:border-box;} body{margin:0;padding:15px;font-size:16px;line-height:1.6;color:#222;background:#E4E4E4;}
      img,video,iframe{max-width:100%;height:auto;} p{margin:0 0 12px;} table{width:100%;border-collapse:collapse;}
      </style></head><body>${safe}</body></html>`;
    return { html: tpl };
  }, [contentHtml]);

  // 删除原先的 getAttachmentName/resolveAttachmentUrl，直接用 URL 字符串
  const getFilenameFromUrl = (url, fallback) => {
    try {
      const u = new URL(url);
      const last = u.pathname.split('/').filter(Boolean).pop();
      if (last) return decodeURIComponent(last);
    } catch (_) {}
    return fallback;
  };

  // 规范化本地保存文件名，移除非法字符与百分号，确保保留扩展名
  const sanitizeLocalFilename = (name, url) => {
    let base = name || 'attachment';
    try {
      // 尝试解码一次，处理 %E5%.. 或 %25E5%.. 的场景
      base = decodeURIComponent(base);
    } catch (_) {}

    // 从 URL 或原始名称中提取扩展名
    let ext = '';
    try {
      const u = new URL(url);
      const last = u.pathname.split('/').filter(Boolean).pop() || '';
      const m = last.match(/(\.[A-Za-z0-9]+)(?:$|\?)/);
      if (m) ext = m[1];
    } catch (_) {}
    const m2 = base.match(/(\.[A-Za-z0-9]+)$/);
    if (m2) ext = m2[1];

    // 移除 iOS/Unix 不允许或易导致歧义的字符，包括 %
    base = base
      .replace(/[\u0000-\u001F\\\/:*?"<>|%#]/g, '_')
      .replace(/\s+/g, '_')
      .replace(/_{2,}/g, '_');

    if (ext && !base.toLowerCase().endsWith(ext.toLowerCase())) {
      base += ext;
    }
    return base;
  };

  // 下载到本地并用系统能力预览（iOS 直接预览/Android 弹出选择应用）
  const handleOpenAttachment = useCallback(async (url, idx) => {
    try {
      if (typeof url !== 'string' || !url.trim()) {
        showError(t('announcement.missingAttachmentUrl'));
        return;
      }

      const nameFromUrl = getFilenameFromUrl(url, t('announcement.attachment', { index: idx + 1 }));

      // iOS 优先用 Safari ViewController 直接预览远程 PDF（和 uniapp 打开系统预览一致的体验）
      if (Platform.OS === 'ios') {
        try {
          await openBrowserAsync(encodeURI(url));
          return;
        } catch (_) {
          // ignore and fallback to local file preview
        }
      }

      const safeName = sanitizeLocalFilename(nameFromUrl, url);
      const localUri = `${FileSystem.cacheDirectory || ''}${safeName}`;

      let targetUri = localUri;
      try {
        const resumable = FileSystem.createDownloadResumable(url, localUri);
        const res = await resumable.downloadAsync();
        targetUri = res?.uri || localUri;
      } catch (_) {}

      if (Platform.OS === 'ios') {
        // Use original file URL; no extra encodeURI to avoid double-encoding
        const uri = targetUri.startsWith('file://') ? targetUri : `file://${targetUri}`;
        try {
          await Linking.openURL(uri);
          return;
        } catch (_) {
          const canShare = await Sharing.isAvailableAsync();
          if (canShare) {
            await Sharing.shareAsync(uri, { dialogTitle: t('announcement.previewAttachmentTitle') });
            return;
          }
          showError(t('announcement.deviceNotSupportPreview'));
          return;
        }
      }

      const canShare = await Sharing.isAvailableAsync();
      if (canShare) {
        await Sharing.shareAsync(targetUri, { dialogTitle: t('announcement.previewAttachmentTitle') });
      } else {
        showError(t('announcement.deviceNotSupportPreview'));
      }
    } catch (e) {
      showError(t('announcement.openAttachmentFailed'));
    }
  }, [t]);

  const webViewStyle = useMemo(() => ({ height: webHeight, backgroundColor: 'transparent' }), [webHeight]);

  const renderSkeleton = useCallback(() => (
    <View style={{ flex: 1 }}>
      <View style={{ paddingHorizontal: wp(12), paddingTop: wp(12), paddingBottom: wp(20) }}>
        {/* 头部骨架 */}
        <View style={styles.headerCard}>
          <YStack gap={wp(10)}>
            <View style={styles.skeletonTitle} />
            <View style={styles.skeletonDate} />
          </YStack>
        </View>
        {/* 内容骨架 */}
        <View style={styles.bodyCard}>
          <View style={styles.htmlBox}>
            <View style={styles.skeletonHtmlBlock} />
            <View style={[styles.skeletonHtmlBlock, { width: '90%' }]} />
            <View style={[styles.skeletonHtmlBlock, { width: '80%' }]} />
          </View>
          <YStack gap={wp(8)} marginTop={wp(12)}>
            <View style={styles.skeletonAttachment} />
            <View style={styles.skeletonAttachment} />
          </YStack>
        </View>
      </View>
    </View>
  ), []);

  return (
    <View flex={1}>
      <ExpoImage
        source={require('@/assets/images/backgrounds/home-bg.webp')}
        style={StyleSheet.absoluteFill}
        contentFit="cover"
        transition={0}
        pointerEvents="none"
        cachePolicy="memory-disk"
      />
      <View flex={1}>
        <CustomHeader title={t('announcement.detailTitle')} />
        {/* 内容与骨架交叉淡入 */}
        <View style={{ flex: 1 }}>
          {skeletonVisible && (
            <Animated.View style={[StyleSheet.absoluteFill, skeletonAnimatedStyle]}>
              {renderSkeleton()}
            </Animated.View>
          )}
          <Animated.View style={[{ flex: 1 }, contentAnimatedStyle]}>
            {/* 整体滚动，标题吸顶；外层留白，卡片内含标题/时间/内容/附件 */}
            <ScrollView
              style={{ flex: 1 }}
              contentContainerStyle={{ paddingHorizontal: wp(12), paddingTop: wp(12), paddingBottom: wp(20) }}
              stickyHeaderIndices={[0]}
              showsVerticalScrollIndicator={false}
            >
              {/* 吸顶标题区（卡片上半部分） */}
              <View style={styles.headerCard}>
                <YStack gap={wp(10)}>
                  <CustomText style={styles.title}>{title || '-'}</CustomText>
                  <CustomText style={styles.date}>{date || '-'}</CustomText>
                </YStack>
              </View>

              {/* 卡片下半部分：内容和附件 */}
              <View style={styles.bodyCard}>
                <View style={styles.htmlBox}>
                  <WebView
                    originWhitelist={["*"]}
                    source={htmlSource}
                    injectedJavaScript={injectedJS}
                    onMessage={onMessage}
                    javaScriptEnabled
                    domStorageEnabled
                    scrollEnabled={false}
                    showsVerticalScrollIndicator={false}
                    style={webViewStyle}
                  />
                </View>

                {attachments?.length > 0 && (
                  <YStack gap={wp(8)} marginTop={wp(12)}>
                    {attachments.map((it, idx) => (
                      <CustomText
                        key={typeof it === 'string' ? it : String(idx)}
                        style={styles.attachment}
                        numberOfLines={1}
                        onPress={() => handleOpenAttachment(it, idx)}
                      >
                        {t('announcement.attachment', { index: idx + 1 })}
                      </CustomText>
                    ))}
                  </YStack>
                )}
              </View>
            </ScrollView>
          </Animated.View>
        </View>
      </View>

      {/* 本地图片预览已移除，改为使用全局 CustomImagePreview.open */}
    </View>
  );
};

export default AnnouncementDetailsScreen;

const RADIUS = wp(8);

const styles = StyleSheet.create({
  headerCard: {
    backgroundColor: '#fff',
    paddingHorizontal: wp(12),
    paddingVertical: wp(12),
    borderTopLeftRadius: RADIUS,
    borderTopRightRadius: RADIUS,
    shadowColor: '#00000020',
    shadowOpacity: 0.08,
    shadowRadius: 4,
    elevation: 2,
  },
  bodyCard: {
    backgroundColor: '#fff',
    paddingHorizontal: wp(12),
    paddingVertical: wp(12),
    borderBottomLeftRadius: RADIUS,
    borderBottomRightRadius: RADIUS,
  },
  title: {
    flex: 1,
    color: '#191919',
    fontSize: sp(16),
    fontFamily: 'Bold',
    paddingRight: wp(10),
    lineHeight: wp(24),
  },
  date: {
    color: '#A1A1A1',
    fontSize: sp(12),
    marginTop: wp(6),
    alignSelf: 'flex-end',
  },
  htmlBox: {
    backgroundColor: '#E4E4E4',
    borderRadius: RADIUS,
    overflow: 'hidden',
    marginTop: wp(10),
  },
  attachment: {
    color: '#6C63FF',
    fontSize: sp(14),
  },
  // 骨架样式
  skeletonTitle: {
    width: '70%',
    height: wp(20),
    backgroundColor: '#F2F3F5',
    borderRadius: wp(4),
  },
  skeletonDate: {
    width: wp(100),
    height: wp(12),
    backgroundColor: '#F2F3F5',
    borderRadius: wp(4),
    alignSelf: 'flex-end',
    marginTop: wp(6),
  },
  skeletonHtmlBlock: {
    width: '100%',
    height: wp(14),
    backgroundColor: '#F2F3F5',
    borderRadius: wp(4),
    marginVertical: wp(8),
  },
  skeletonAttachment: {
    width: wp(160),
    height: wp(14),
    backgroundColor: '#F2F3F5',
    borderRadius: wp(4),
  },
});
