import React, { useCallback, useEffect, useRef, useState } from 'react';
import { StatusBar } from 'expo-status-bar';
import { Stack } from 'expo-router';
import { AppState, DeviceEventEmitter, Platform, Text, View } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { ThemeProvider, useTheme } from '../theme';
import { useLedgerStore } from '../store/ledgerStore';
import { useImportStore } from '../store/importStore';
import { useSettingsStore } from '../store/settingsStore';
import { useMetadataStore } from '../store/metadataStore';
import { parseDecimal } from '../domain/core/decimal';
import { FileSystemBackend } from '../services/data/fileSystemBackend';
import { useNumpadUiStore } from '../store/numpadUiStore';
import { useT } from '../i18n';
import { LockScreen } from '../components/layout/LockScreen';
import { NumpadSheetHost } from '../components/form/NumpadSheetHost';
import { ToastProvider } from '../components/ui/Toast';
import { OnboardingScreen } from './_onboarding';
import { setupDeepLinking } from '../services/deepLink';
import { initPersistence, flushPersistence } from '../store/storePersistence';
import * as FileSystem from 'expo-file-system/legacy';
import { useRouter } from 'expo-router';
import { parseNotification } from '../services/notification';
import { parseSms } from '../services/sms';
import { processScreenshotEvent, handleIncomingBillEvent, parseAndProcessAccessibilityTexts, loadProcessedTxKeys, ensureBillingListenerRegistered, removeBillingListener } from '../services/automation/automationPipeline';
import { getAccessibilityBridge } from '../services/automation/accessibilityBridge';
import { pushFloatingUiConfig } from '../services/automation/floatingUiConfig';
import { ensureOcrModels } from '../services/ocr/modelDownloader';
import { logger } from '../utils/logger';
import { sanitizeLogText } from '../utils/sanitize';
import { expoLogBackend } from '../services/logBackend';

let lastSignature = '';
let lastProcessedTime = 0;

/**
 * 原生浮层 UI 配置同步（P6 FloatingUiConfig 契约）：
 * 启动 / 主题切换 / 语言切换时向原生推送 colors + labels。
 * 挂在 ThemeProvider 内部，渲染 null。
 */
function FloatingUiConfigSyncer() {
  const { theme } = useTheme();
  const locale = useSettingsStore(s => s.locale);
  const t = useT();
  useEffect(() => {
    // useT() 每次渲染返回新 bind，故依赖用 locale 而非 t；
    // locale 变化时 useT 内部已将 i18n.locale 指向新语言
    void pushFloatingUiConfig(theme, t);
    // eslint-disable-next-line react-hooks/exhaustive-deps -- t 每次渲染都是新引用，用 locale 代替
  }, [theme, locale]);
  return null;
}

/** 原生悬浮窗跳转 App 事件类型 */
interface NativeOpenAppEvent {
  draftId?: string;
  confirmed?: boolean;
  account?: string;
  category?: string;
  amount?: string;
  time?: string;
  direction?: string;
  merchant?: string;
  narration?: string;
  currency?: string;
}

/** 示例账本（后续由文件选择器导入，当前 demo 用内置）。 */
const SAMPLE_LEDGER = {
  path: 'main.bean',
  content: `option "operating_currency" "CNY"
`,
};

/** 内层布局：引导/锁屏/路由三态切换。 */
function AppShell() {
  const { theme, isDark } = useTheme();
  const t = useT();
  const router = useRouter();
  
  const loadLedger = useLedgerStore(s => s.loadLedger);
  const setContext = useImportStore(s => s.setContext);
  const appLockEnabled = useSettingsStore(s => s.appLockEnabled);
  const setOnboardingCompleted = useSettingsStore(s => s.setOnboardingCompleted);
  const [phase, setPhase] = useState<'loading' | 'onboarding' | 'locked' | 'ready'>('loading');
  const [privacyOverlay, setPrivacyOverlay] = useState(false);

  const lastMainFileRef = useRef<{ modificationTime?: number; size?: number } | null>(null);
  const persistenceInitRef = useRef(false);
  const lastCheckTimeRef = useRef(0);

  const checkAndReloadLedger = useCallback(async () => {
    // 节流：2 秒内不重复检查
    const now = Date.now();
    if (now - lastCheckTimeRef.current < 2000) return;
    lastCheckTimeRef.current = now;

    const mainPath = FileSystem.documentDirectory + 'main.bean';
    try {
      const info = await FileSystem.getInfoAsync(mainPath);
      if (!info.exists) return;

      const currentMtime = info.modificationTime;
      const currentSize = info.size;

      // 如果是第一次加载，或者文件时间/大小发生了改变，则重新读取并加载
      if (
        !lastMainFileRef.current ||
        lastMainFileRef.current.modificationTime !== currentMtime ||
        lastMainFileRef.current.size !== currentSize
      ) {
        logger.info('layout', `检测到 main.bean 发生外部文件修改，正在重新加载... (mtime: ${currentMtime}, size: ${currentSize})`);
        const content = await FileSystem.readAsStringAsync(mainPath);
        const rules = useMetadataStore.getState().rules;
        const categories = useMetadataStore.getState().categories;
        
        await loadLedger([{ path: 'main.bean', content }], new FileSystemBackend());
        setContext({ rules, categories });
        
        lastMainFileRef.current = { modificationTime: currentMtime, size: currentSize };
        logger.info('layout', 'main.bean 重新解析并加载成功');
      }
    } catch (e) {
      logger.error('layout', 'checkAndReloadLedger 失败', e);
    }
  }, [loadLedger, setContext]);

  useEffect(() => {
    if (persistenceInitRef.current) return;
    persistenceInitRef.current = true;
    // 1. 初始化持久化并还原数据
    initPersistence().then(async () => {
      // 初始化磁盘日志持久化系统
      logger.initFileBackend(expoLogBackend).catch(e => {
        logger.warn('layout', '磁盘日志初始化失败', e);
      });

      // 加载已处理的交易键（跨会话去重）
      await loadProcessedTxKeys();

      // OCR 模型改为按需下载（用户触发 OCR 时才下载，不在启动时自动下载 ~30MB）
      // 若已有模型则静默初始化原生引擎
      const settings = useSettingsStore.getState();
      if (settings.ocrModelDir) {
        ensureOcrModels().catch((e) => { logger.warn('layout', '[OCR模型] 静默初始化失败', e); });
      }

      const mainPath = FileSystem.documentDirectory + 'main.bean';

      // 架构说明：main.bean 作为主账本文件，包含所有 Beancount 指令（open/close/option/include 等），
      // App 直接对其进行读写与解析。

      // 2. 检查并读取本地真实主账本
      FileSystem.getInfoAsync(mainPath).then(async (info) => {
        let content = SAMPLE_LEDGER.content;
        if (info.exists) {
          content = await FileSystem.readAsStringAsync(mainPath);
          lastMainFileRef.current = { modificationTime: info.modificationTime, size: info.size };
        }

        const rules = useMetadataStore.getState().rules;
        const categories = useMetadataStore.getState().categories;

        loadLedger([{ path: 'main.bean', content }], new FileSystemBackend()).then(() => {
          setContext({ rules, categories });
          
          const completed = useSettingsStore.getState().onboardingCompleted;
          const locked = useSettingsStore.getState().appLockEnabled;
          const floatingEnabled = useSettingsStore.getState().floatingBallEnabled;

          // 开启/初始化时同步悬浮球开关至原生无障碍服务
          const bridge = getAccessibilityBridge();
          if (bridge) {
            bridge.setFloatingBallEnabled(floatingEnabled).catch((e) => { logger.debug('layout', '[悬浮球] 同步开关失败', e); });
          }

          if (!completed) {
            setPhase('onboarding');
          } else if (locked) {
            setPhase('locked');
          } else {
            setPhase('ready');
          }
        }).catch((e) => {
          // 加载失败时仍进入引导流程（而非跳过），让用户有机会重新导入账本
          logger.warn('layout', `Ledger load failed: ${e instanceof Error ? e.message : String(e)}`);
          setPhase('onboarding');
        });
      });
    });
  }, [loadLedger, setContext]);

  // 3. 注册深度链接监听（plan.md「1.5」），注入真实的 router 导航行为
  useEffect(() => {
    if (phase === 'ready') {
      const cleanup = setupDeepLinking((action) => {
        if (action.type === 'add-transaction') {
          useNumpadUiStore.getState().open();
        } else if (action.type === 'open-tab') {
          if (action.tab === 'home') router.push('/(tabs)');
          else if (action.tab === 'transactions') router.push('/(tabs)/transactions');
          else if (action.tab === 'import') router.push('/import');
          else if (action.tab === 'rules') router.push('/rules');
          else if (action.tab === 'settings') router.push('/(tabs)/settings');
        } else if (action.type === 'import-csv') {
          router.push('/import');
        } else if (action.type === 'ocr-camera' || action.type === 'ocr-image') {
          useNumpadUiStore.getState().open({ autoOcr: true });
        } else if (action.type === 'voice-input') {
          router.push('/(tabs)/settings');
        }
      });
      return cleanup;
    }
  }, [phase, router]);

  // 4. 监听原生自动化事件（通知/短信/截图）→ automationStore
  // 通知/短信事件是原始文本，需先经 parseNotification/parseSms 解析为 ImportedEvent
  // 截图事件是原始 base64 图片，需先经 OcrProcessor 识别为 ImportedEvent
  useEffect(() => {
    if (phase !== 'ready' || Platform.OS !== 'android') return;

    // 注册全局 billingConfirmed 监听器（浮窗确认入账回调）
    ensureBillingListenerRegistered();

    const subscriptions = [
      DeviceEventEmitter.addListener('billingNotification', (event) => {
        try {
          const safeText = sanitizeLogText(event.text || '');
          logger.debug('layout', `收到原生通知, 包名: ${event.packageName}, 标题: ${event.title}`, { raw: safeText });
          const bill = parseNotification(event);
          if (bill) {
            logger.debug('layout', `通知解析成功，进入账单管道`);
            handleIncomingBillEvent('notification', bill, `[${event.title}] ${event.text}`);
          } else {
            logger.debug('layout', `通知未匹配为账单: [${event.title}]`, { raw: safeText });
          }
        } catch (e) {
          logger.error('layout', '[通知] 解析失败', e);
        }
      }),
      DeviceEventEmitter.addListener('billingSms', (event) => {
        try {
          const safeBody = sanitizeLogText(event.body || '');
          logger.debug('layout', `收到原生短信, 发送者: ${event.address || event.sender || '未知'}`, { raw: safeBody });
          const smsEvent = {
            sender: event.sender || event.address || '',
            body: event.body,
            timestamp: event.timestamp || Date.now(),
          };
          const bill = parseSms(smsEvent);
          if (bill) {
            logger.debug('layout', `短信解析成功，进入账单管道`);
            handleIncomingBillEvent('sms', bill, event.body);
          } else {
            logger.debug('layout', `短信未匹配为账单`, { raw: safeBody });
          }
        } catch (e) {
          logger.error('layout', '[短信] 解析失败', e);
        }
      }),
      DeviceEventEmitter.addListener('billingScreenshot', async (event) => {
        try {
          logger.debug('layout', `收到原生截图/无障碍截图, 包名: ${event.packageName}`);
          await processScreenshotEvent(event);
        } catch (e) {
          logger.error('layout', `[截图] OCR 处理失败 (包名: ${event.packageName}, 是否有Base64: ${Boolean(event.imageBase64)})`, e instanceof Error ? { message: e.message, stack: e.stack } : String(e));
        }
      }),
      DeviceEventEmitter.addListener('billingOpenApp', async (event) => {
        try {
          const res = event as NativeOpenAppEvent;
          logger.info('layout', `[悬浮窗跳转] 收到请求: 商户=${res.merchant ?? '无'}, 金额=${res.amount ?? '无'}, confirmed=${res.confirmed ?? false}`);
          if (res.confirmed) {
            // 已由原生悬浮窗确认入账，前端仅记录日志或提示
            return;
          }
          if (!res.amount && !res.merchant) {
            logger.warn('layout', '[悬浮窗跳转] 数据不完整，跳过', { draftId: res.draftId, amount: res.amount, merchant: res.merchant });
            return;
          }
          const amt = res.amount ?? '0';
          try {
            parseDecimal(amt);
          } catch {
            if (amt.length > 0) {
              logger.warn('layout', 'billingOpenApp 金额格式错误', amt);
            } else {
              logger.warn('layout', 'billingOpenApp 金额无效', amt);
            }
            return;
          }
          const direction = res.direction ?? 'expense';
          const categoryAccount = res.category ?? 'Expenses:未分类';
          const sourceAccount = res.account ?? 'Assets:未知';
          const currency = res.currency ?? 'CNY';
          const postings = [
            { account: sourceAccount, amount: direction === 'expense' ? `-${amt}` : amt, currency },
            { account: categoryAccount, amount: direction === 'expense' ? amt : `-${amt}`, currency }
          ];
          const draft = {
            date: res.time ? res.time.split(' ')[0] : new Date().toISOString().split('T')[0],
            payee: res.merchant || undefined,
            narration: res.narration || '',
            postings
          };
          useNumpadUiStore.getState().open({ draftJson: JSON.stringify(draft) });
        } catch (e) {
          logger.error('layout', '[悬浮窗跳转] 处理失败', e);
        }
      }),
      DeviceEventEmitter.addListener('billingPageRemembered', (event) => {
        logger.debug('layout', `[无障碍调试] 成功记住页面签名: ${event.signature} (包名: ${event.package}, 类名: ${event.activity})`, { texts: (event.texts ?? []).map(sanitizeLogText) });
      }),
      DeviceEventEmitter.addListener('billingDebugNodes', async (event) => {
        const { package: pkg, activity, texts, isManual } = event;

        // 仅处理手动触发（悬浮球点击），自动监听已移除（微信 8.0.52+ 混淆节点文本，自动监听无意义）
        if (!isManual) return;

        const sigKey = `${pkg}|${activity}`;
        logger.info('layout', `[无障碍识别] 手动触发 | 页面: ${sigKey} | 节点数: ${texts?.length ?? 0}`, { texts: (texts ?? []).map(sanitizeLogText) });

        try {
          const bridge = getAccessibilityBridge();
          if (!texts || texts.length === 0) {
            logger.info('layout', '[无障碍识别] 节点文本为空（可能是微信等混淆应用），降级触发 OCR 截图识别');
            bridge?.triggerManualOcr();
            return;
          }

          // 尝试直接文本解析（传递完整文本，非截断）
          const success = await parseAndProcessAccessibilityTexts(texts, pkg);
          if (!success) {
            logger.info('layout', '[无障碍识别] 直接文本解析未成功，降级触发 OCR 截图识别');
            bridge?.triggerManualOcr();
          }
        } catch (e) {
          logger.error('layout', `[无障碍识别] 执行失败 (页面: ${sigKey})`, e);
        }
      }),
    ];

    return () => {
      subscriptions.forEach(s => s.remove());
      removeBillingListener();
    };
  }, [phase]);

  // 5. 隐私模糊（plan.md「0.4 隐私模糊」）：App 进入后台/非活跃时遮盖内容
  useEffect(() => {
    const sub = AppState.addEventListener('change', (state) => {
      // 切到后台/非活跃时立即遮盖并同步持久化，回到前台时移除
      setPrivacyOverlay(state !== 'active');
      if (state !== 'active') {
        flushPersistence().catch(e => logger.error('layout', 'Failed to flush persistence on background', e));
      }
      if (state === 'active' && phase === 'ready') {
        checkAndReloadLedger();
      }
    });
    return () => sub.remove();
  }, [phase, checkAndReloadLedger]);

  // loading 状态
  if (phase === 'loading') {
    return (
      <SafeAreaView style={{ flex: 1, backgroundColor: theme.colors.bgPrimary, alignItems: 'center', justifyContent: 'center' }}>
        <Text style={{ color: theme.colors.fgSecondary }}>{t('app.name')}</Text>
      </SafeAreaView>
    );
  }

  // 引导流程
  if (phase === 'onboarding') {
    return (
      <ThemeProvider>
        <OnboardingScreen onComplete={() => {
          setOnboardingCompleted(true);
          setPhase(appLockEnabled ? 'locked' : 'ready');
        }} />
      </ThemeProvider>
    );
  }

  // 锁屏
  if (phase === 'locked') {
    return <LockScreen onUnlock={() => setPhase('ready')} />;
  }

  // ready：主应用
  return (
    <View style={{ flex: 1, backgroundColor: theme.colors.bgPrimary }}>
      <StatusBar style={isDark ? 'light' : 'dark'} />
      <Stack screenOptions={{ headerShown: false, contentStyle: { backgroundColor: theme.colors.bgPrimary } }}>
        <Stack.Screen name="(tabs)" />
        <Stack.Screen name="transaction/[id]" options={{ headerShown: false }} />
        <Stack.Screen name="category/index" options={{ headerShown: false }} />
        <Stack.Screen name="tag/index" options={{ headerShown: false }} />
        <Stack.Screen name="budget/index" options={{ headerShown: false }} />
        <Stack.Screen name="account/index" options={{ headerShown: false }} />
        <Stack.Screen name="import/index" options={{ headerShown: false }} />
        <Stack.Screen name="rules/index" options={{ headerShown: false }} />
        <Stack.Screen name="settings/ai" options={{ headerShown: false }} />
        <Stack.Screen name="settings/sync" options={{ headerShown: false }} />
        <Stack.Screen name="settings/preferences" options={{ headerShown: false }} />
        <Stack.Screen name="settings/diagnostics" options={{ headerShown: false }} />
        <Stack.Screen name="recurring/index" options={{ headerShown: false }} />
        <Stack.Screen name="ai/chat" options={{ headerShown: false }} />
        <Stack.Screen name="remark-template/index" options={{ headerShown: false }} />
        <Stack.Screen name="automation/index" options={{ headerShown: false }} />
        <Stack.Screen name="credit-card/index" options={{ headerShown: false }} />
      </Stack>
      <NumpadSheetHost />
      {/* 隐私遮罩（plan.md「0.4」）：App 切后台时遮盖内容并拦截所有手势 */}
      {privacyOverlay && (
        <View
          style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, backgroundColor: theme.colors.bgPrimary, zIndex: 99999 }}
          pointerEvents="auto"
          accessible={false}
        />
      )}
    </View>
  );
}

/** 根布局：GestureHandlerRootView（左滑手势）包裹 ThemeProvider。 */
export default function RootLayout() {
  return (
    <GestureHandlerRootView style={{ flex: 1 }}>
      <ThemeProvider>
        <ToastProvider>
          <FloatingUiConfigSyncer />
          <AppShell />
        </ToastProvider>
      </ThemeProvider>
    </GestureHandlerRootView>
  );
}
