import React, { useEffect, useRef, useState } from 'react';
import {
  View, Text, StyleSheet, TouchableOpacity, Image, Alert, Animated, Easing,
} from 'react-native';
import { useLocalSearchParams, useRouter } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';
import { CameraView, useCameraPermissions } from 'expo-camera';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import * as ImagePicker from 'expo-image-picker';
import * as ImageManipulator from 'expo-image-manipulator';
import * as Haptics from 'expo-haptics';
import * as AppleAuthentication from 'expo-apple-authentication';
import Constants from 'expo-constants';
import { ShareIntentModule } from 'expo-share-intent';
import { useSafeAnalytics } from '../services/analytics';
import { useApp } from '../context/AppContext';
import { useColors } from '../constants/Colors';
import { PlantRecognitionService } from '../services/plantRecognitionService';
import { IdentificationResult } from '../types';
import { ResultCard } from '../components/ResultCard';
import { backendApiClient, isInsufficientCreditsError, isNetworkError, isTimeoutError } from '../services/backend/backendApiClient';
import { isBackendApiError } from '../services/backend/contracts';
import { createIdempotencyKey } from '../utils/idempotency';
import { AuthService } from '../services/authService';
import { getMockPlantByImage } from '../services/backend/mockCatalog';
import { consumeSharedImageUri, SHARE_INTENT_KEY } from '../utils/shareHandoff';

const HEALTH_CHECK_CREDIT_COST = 2;
const DEMO_SCAN_LIMIT = 5;

const getBillingCopy = (language: 'de' | 'en' | 'es') => {
  if (language === 'de') {
    return {
      creditsLabel: 'Credits',
      noCreditsTitle: 'Keine Credits mehr',
      noCreditsMessage: 'Du hast keine Credits mehr fuer KI-Scans. Upgrade oder Top-up im Profil.',
      healthNoCreditsMessage: `Du brauchst ${HEALTH_CHECK_CREDIT_COST} Credits fuer den Health-Check.`,
      managePlan: 'Plan verwalten',
      dismiss: 'Schliessen',
      genericErrorTitle: 'Fehler',
      genericErrorMessage: 'Analyse fehlgeschlagen.',
      noConnectionTitle: 'Keine Verbindung',
      noConnectionMessage: 'Keine Verbindung zum Server. Bitte prüfe deine Internetverbindung und versuche es erneut.',
      timeoutTitle: 'Scan zu langsam',
      timeoutMessage: 'Die Analyse hat zu lange gedauert. Bitte erneut versuchen.',
      retryLabel: 'Erneut versuchen',
      notAPlantTitle: 'Keine Pflanze erkannt',
      notAPlantMessage: 'Das Bild zeigt keine erkennbare Pflanze. Bitte fotografiere eine Pflanze und versuche es erneut.',
      providerErrorMessage: 'KI-Scan gerade nicht verfügbar. Bitte versuche es erneut.',
      healthProviderErrorMessage: 'KI-Health-Check gerade nicht verfügbar. Bitte versuche es erneut.',
      healthTitle: 'Health Check',
      healthDoneTitle: 'Health Check abgeschlossen',
      healthDoneMessage: 'Neues Foto wurde geprueft und zur Galerie hinzugefuegt.',
      signupLabel: 'Registrieren',
      demoTitle: 'Rettungsplan bereit',
      demoMessage: 'Wir haben mögliche Ursachen erkannt. Schalte die vollständige KI-Diagnose und deinen 7-Tage-Rettungsplan frei.',
      demoNoCreditsTitle: 'Demo-Scans aufgebraucht',
      demoNoCreditsMessage: 'Du hast deine 5 kostenlosen Demo-Scans auf diesem Gerät genutzt. Starte Pro, um weiter Pflanzen zu scannen.',
      demoCreditsRemaining: (count: number) => `${count} Demo-Scans übrig`,
      appleCta: 'Mit Apple fortfahren',
      emailCta: 'Mit E-Mail fortfahren',
      unlockCta: 'Vollständige Diagnose freischalten',
    };
  }

  if (language === 'es') {
    return {
      creditsLabel: 'Creditos',
      noCreditsTitle: 'Sin creditos',
      noCreditsMessage: 'No tienes creditos para escaneos AI. Actualiza o compra top-up en Perfil.',
      healthNoCreditsMessage: `Necesitas ${HEALTH_CHECK_CREDIT_COST} creditos para el health-check.`,
      managePlan: 'Gestionar plan',
      dismiss: 'Cerrar',
      genericErrorTitle: 'Error',
      genericErrorMessage: 'Analisis fallido.',
      noConnectionTitle: 'Sin conexión',
      noConnectionMessage: 'Sin conexión al servidor. Comprueba tu internet e inténtalo de nuevo.',
      timeoutTitle: 'Escaneo lento',
      timeoutMessage: 'El análisis tardó demasiado. Inténtalo de nuevo.',
      retryLabel: 'Reintentar',
      notAPlantTitle: 'No es una planta',
      notAPlantMessage: 'La imagen no muestra una planta reconocible. Por favor fotografía una planta e inténtalo de nuevo.',
      providerErrorMessage: 'Escaneo IA no disponible ahora. Inténtalo de nuevo.',
      healthProviderErrorMessage: 'Health-check IA no disponible ahora. Inténtalo de nuevo.',
      healthTitle: 'Health Check',
      healthDoneTitle: 'Health-check completado',
      healthDoneMessage: 'La foto nueva fue analizada y guardada en la galeria.',
      signupLabel: 'Registrarse',
      demoTitle: 'Plan de rescate listo',
      demoMessage: 'Detectamos posibles causas. Desbloquea el diagnóstico completo con IA y tu plan de rescate de 7 días.',
      demoNoCreditsTitle: 'Escaneos demo agotados',
      demoNoCreditsMessage: 'Ya usaste tus 5 escaneos demo gratuitos en este dispositivo. Inicia Pro para seguir escaneando plantas.',
      demoCreditsRemaining: (count: number) => `${count} escaneos demo restantes`,
      appleCta: 'Continuar con Apple',
      emailCta: 'Continuar con email',
      unlockCta: 'Desbloquear diagnóstico completo',
    };
  }

  return {
    creditsLabel: 'Credits',
    noCreditsTitle: 'No credits left',
    noCreditsMessage: 'You have no AI scan credits left. Upgrade or buy a top-up in Profile.',
    healthNoCreditsMessage: `You need ${HEALTH_CHECK_CREDIT_COST} credits for the health check.`,
    managePlan: 'Manage plan',
    dismiss: 'Close',
    genericErrorTitle: 'Error',
    genericErrorMessage: 'Analysis failed.',
    noConnectionTitle: 'No connection',
    noConnectionMessage: 'Could not reach the server. Check your internet connection and try again.',
    timeoutTitle: 'Scan Too Slow',
    timeoutMessage: 'Analysis took too long. Please try again.',
    retryLabel: 'Try again',
    notAPlantTitle: 'No plant detected',
    notAPlantMessage: 'The image does not show a recognizable plant. Please photograph a plant and try again.',
    providerErrorMessage: 'AI scan is currently unavailable. Please try again.',
    healthProviderErrorMessage: 'AI health check is currently unavailable. Please try again.',
    healthTitle: 'Health Check',
    healthDoneTitle: 'Health Check Complete',
    healthDoneMessage: 'The new photo was analyzed and added to gallery.',
    signupLabel: 'Sign Up',
    demoTitle: 'Rescue plan ready',
    demoMessage: 'We found possible causes. Unlock the full AI diagnosis and your 7-day rescue plan.',
    demoNoCreditsTitle: 'Demo scans used',
    demoNoCreditsMessage: 'You used your 5 free demo scans on this device. Start Pro to keep scanning plants.',
    demoCreditsRemaining: (count: number) => `${count} demo scans left`,
    appleCta: 'Continue with Apple',
    emailCta: 'Continue with email',
    unlockCta: 'Unlock full diagnosis',
  };
};

export default function ScannerScreen() {
  const params = useLocalSearchParams<{ mode?: string; plantId?: string; sharedImageKey?: string; sharedImageUri?: string }>();
  const posthog = useSafeAnalytics();
  const {
    isDarkMode,
    colorPalette,
    language,
    t,
    savePlant,
    plants,
    updatePlant,
    billingSummary,
    refreshBillingSummary,
    isLoadingBilling,
    session,
    hydrateSession,
    setPendingPlant,
    guestScanCount,
    incrementGuestScanCount,
  } = useApp();
  const colors = useColors(isDarkMode, colorPalette);
  const router = useRouter();
  const insets = useSafeAreaInsets();
  const billingCopy = getBillingCopy(language);
  const isHealthMode = params.mode === 'health';
  const healthPlantId = Array.isArray(params.plantId) ? params.plantId[0] : params.plantId;
  const healthPlant = isHealthMode && healthPlantId
    ? plants.find((item) => item.id === healthPlantId)
    : null;
  const sharedImageUri = Array.isArray(params.sharedImageUri)
    ? params.sharedImageUri[0]
    : params.sharedImageUri;
  const sharedImageKey = Array.isArray(params.sharedImageKey)
    ? params.sharedImageKey[0]
    : params.sharedImageKey;
  const hasActiveEntitlement = billingSummary?.entitlement?.plan === 'pro'
    && billingSummary?.entitlement?.status === 'active';
  const isDemoMode = !hasActiveEntitlement;
  const availableCredits = hasActiveEntitlement ? (billingSummary?.credits.available ?? 0) : 0;
  const demoScansRemaining = Math.max(0, DEMO_SCAN_LIMIT - guestScanCount);

  const [permission, requestPermission] = useCameraPermissions();
  const [selectedImage, setSelectedImage] = useState<string | null>(null);
  const [isAnalyzing, setIsAnalyzing] = useState(false);
  const [isAuthLoading, setIsAuthLoading] = useState(false);
  const [appleAvailable, setAppleAvailable] = useState(false);
  const [analysisProgress, setAnalysisProgress] = useState(0);
  const [analysisResult, setAnalysisResult] = useState<IdentificationResult | null>(null);
  const [demoResultVisible, setDemoResultVisible] = useState(false);
  const cameraRef = useRef<CameraView>(null);
  const scanLineProgress = useRef(new Animated.Value(0)).current;
  const scanPulse = useRef(new Animated.Value(0)).current;
  const isExpoGo = Constants.appOwnership === 'expo';

  useEffect(() => {
    if (isExpoGo) {
      setAppleAvailable(false);
      return;
    }
    let mounted = true;
    AppleAuthentication.isAvailableAsync()
      .then((available) => {
        if (mounted) setAppleAvailable(available);
      })
      .catch(() => {
        if (mounted) setAppleAvailable(false);
      });
    return () => {
      mounted = false;
    };
  }, [isExpoGo]);

  const lastProcessedShareToken = useRef<string | null>(null);
  const sharedAnalysisInFlightToken = useRef<string | null>(null);
  const resizeForAnalysisRef = useRef<(uri: string) => Promise<string>>(async (uri) => uri);
  const analyzeImageRef = useRef<(imageUri: string, galleryImageUri?: string) => Promise<void>>(async () => {});

  useEffect(() => {
    if (!isAnalyzing) {
      scanLineProgress.stopAnimation();
      scanLineProgress.setValue(0);
      scanPulse.stopAnimation();
      scanPulse.setValue(0);
      return;
    }

    const lineAnimation = Animated.loop(
      Animated.sequence([
        Animated.timing(scanLineProgress, {
          toValue: 1,
          duration: 1500,
          easing: Easing.inOut(Easing.quad),
          useNativeDriver: true,
        }),
        Animated.timing(scanLineProgress, {
          toValue: 0,
          duration: 1500,
          easing: Easing.inOut(Easing.quad),
          useNativeDriver: true,
        }),
      ])
    );

    const pulseAnimation = Animated.loop(
      Animated.sequence([
        Animated.timing(scanPulse, { toValue: 1, duration: 900, useNativeDriver: true }),
        Animated.timing(scanPulse, { toValue: 0, duration: 900, useNativeDriver: true }),
      ])
    );

    lineAnimation.start();
    pulseAnimation.start();

    return () => {
      lineAnimation.stop();
      pulseAnimation.stop();
    };
  }, [isAnalyzing, scanLineProgress, scanPulse]);

  const resizeForAnalysis = async (uri: string): Promise<string> => {
    if (uri.startsWith('data:')) return uri;
    try {
      const result = await ImageManipulator.manipulateAsync(
        uri,
        [{ resize: { width: 1280 } }],
        { compress: 0.9, format: ImageManipulator.SaveFormat.JPEG, base64: true },
      );
      return result.base64 ? `data:image/jpeg;base64,${result.base64}` : result.uri;
    } catch {
      return uri;
    }
  };

  const analyzeImage = async (imageUri: string, galleryImageUri?: string) => {
    if (isAnalyzing) return;

    if (isDemoMode && guestScanCount >= DEMO_SCAN_LIMIT) {
      Alert.alert(
        billingCopy.demoNoCreditsTitle,
        billingCopy.demoNoCreditsMessage,
        [
          { text: billingCopy.dismiss, style: 'cancel' },
          {
            text: billingCopy.managePlan,
            onPress: () => router.replace('/profile/billing'),
          },
        ],
      );
      return;
    }

    if (!isDemoMode && availableCredits <= 0) {
      Alert.alert(
        billingCopy.noCreditsTitle,
        isHealthMode ? billingCopy.healthNoCreditsMessage : billingCopy.noCreditsMessage,
        [
          { text: billingCopy.dismiss, style: 'cancel' },
          {
            text: billingCopy.managePlan,
            onPress: () => router.replace('/profile/billing'),
          },
        ],
      );
      return;
    }

    setIsAnalyzing(true);
    setAnalysisProgress(0);
    setAnalysisResult(null);
    setDemoResultVisible(false);

    const startTime = Date.now();

    const progressInterval = setInterval(() => {
      setAnalysisProgress((prev) => {
        if (prev < 30) return prev + Math.random() * 8;
        if (prev < 70) return prev + Math.random() * 2;
        if (prev < 90) return prev + 0.5;
        return prev;
      });
    }, 150);

    try {
      if (isDemoMode) {
        posthog.capture('demo_scan_started', {
          authenticated: Boolean(session),
          scan_type: isHealthMode ? 'health_check' : 'identification',
          demo_scans_used: guestScanCount,
          demo_scans_remaining: demoScansRemaining,
        });
        await new Promise(resolve => setTimeout(resolve, 2100));
        setAnalysisProgress(100);
        await Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
        await new Promise(resolve => setTimeout(resolve, 350));
        const demoResult = getMockPlantByImage(galleryImageUri || imageUri, language, true);
        incrementGuestScanCount();
        setAnalysisResult(demoResult);
        posthog.capture('demo_scan_completed', {
          authenticated: Boolean(session),
          latency_ms: Date.now() - startTime,
          demo_scans_used_after: guestScanCount + 1,
        });
        return;
      }

      posthog.capture('paid_scan_started', {
        scan_type: isHealthMode ? 'health_check' : 'identification',
        credits_available: availableCredits,
      });

      if (isHealthMode) {
        if (!healthPlant) {
          Alert.alert(billingCopy.genericErrorTitle, billingCopy.genericErrorMessage);
          setSelectedImage(null);
          setIsAnalyzing(false);
          return;
        }

        const response = await backendApiClient.runHealthCheck({
          idempotencyKey: createIdempotencyKey('health-check', healthPlant.id),
          imageUri,
          language,
          plantContext: {
            name: healthPlant.name,
            botanicalName: healthPlant.botanicalName,
            careInfo: healthPlant.careInfo,
            description: healthPlant.description,
          },
        });

        posthog.capture('llm_generation', {
          scan_type: 'health_check',
          success: true,
          latency_ms: Date.now() - startTime,
        });

        const currentGallery = healthPlant.gallery || [];
        const existingChecks = healthPlant.healthChecks || [];
        const updatedChecks = [response.healthCheck, ...existingChecks].slice(0, 6);
        const updatedPlant = {
          ...healthPlant,
          gallery: galleryImageUri ? [...currentGallery, galleryImageUri] : currentGallery,
          healthChecks: updatedChecks,
        };
        await updatePlant(updatedPlant);
      } else {
        const result = await PlantRecognitionService.identify(imageUri, language, {
          idempotencyKey: createIdempotencyKey('scan-plant'),
        });

        posthog.capture('llm_generation', {
          scan_type: 'identification',
          success: true,
          latency_ms: Date.now() - startTime,
        });

        setAnalysisResult(result);
      }
      setAnalysisProgress(100);
      await Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
      posthog.capture('paid_scan_completed', {
        scan_type: isHealthMode ? 'health_check' : 'identification',
        latency_ms: Date.now() - startTime,
      });
      await new Promise(resolve => setTimeout(resolve, 500));
      setIsAnalyzing(false);
      if (isHealthMode && healthPlant) {
        Alert.alert(billingCopy.healthDoneTitle, billingCopy.healthDoneMessage, [
          { text: billingCopy.dismiss, onPress: () => router.replace(`/plant/${healthPlant.id}`) },
        ]);
      }
    } catch (error) {
      console.error('Analysis failed', error);

      posthog.capture('llm_generation', {
        scan_type: isHealthMode ? 'health_check' : 'identification',
        success: false,
        error_type: isInsufficientCreditsError(error) ? 'insufficient_credits' : 'provider_error',
        latency_ms: Date.now() - startTime,
      });

      if (isInsufficientCreditsError(error)) {
        Alert.alert(
          billingCopy.noCreditsTitle,
          isHealthMode ? billingCopy.healthNoCreditsMessage : billingCopy.noCreditsMessage,
          [
            { text: billingCopy.dismiss, style: 'cancel' },
            {
              text: billingCopy.managePlan,
              onPress: () => router.replace('/profile/billing'),
            },
          ],
        );
      } else if (isTimeoutError(error)) {
        Alert.alert(
          billingCopy.timeoutTitle,
          billingCopy.timeoutMessage,
          [
            { text: billingCopy.dismiss, style: 'cancel' },
            { text: billingCopy.retryLabel, onPress: () => analyzeImage(imageUri, galleryImageUri) },
          ],
        );
      } else if (isNetworkError(error)) {
        Alert.alert(
          billingCopy.noConnectionTitle,
          billingCopy.noConnectionMessage,
          [
            { text: billingCopy.dismiss, style: 'cancel' },
            { text: billingCopy.retryLabel, onPress: () => analyzeImage(imageUri, galleryImageUri) },
          ],
        );
      } else if (isBackendApiError(error) && error.code === 'NOT_A_PLANT') {
        Alert.alert(
          billingCopy.notAPlantTitle,
          billingCopy.notAPlantMessage,
          [{ text: billingCopy.dismiss, style: 'cancel' }],
        );
      } else if (isBackendApiError(error) && error.code === 'PROVIDER_ERROR') {
        Alert.alert(
          billingCopy.genericErrorTitle,
          isHealthMode ? billingCopy.healthProviderErrorMessage : billingCopy.providerErrorMessage,
          [
            { text: billingCopy.dismiss, style: 'cancel' },
            { text: billingCopy.retryLabel, onPress: () => analyzeImage(imageUri, galleryImageUri) },
          ],
        );
      } else {
        Alert.alert(billingCopy.genericErrorTitle, billingCopy.genericErrorMessage);
      }
      setSelectedImage(null);
      setIsAnalyzing(false);
    } finally {
      clearInterval(progressInterval);
      setIsAnalyzing(false);
      if (!isDemoMode) {
        await refreshBillingSummary();
      }
    }
  };

  useEffect(() => {
    resizeForAnalysisRef.current = resizeForAnalysis;
    analyzeImageRef.current = analyzeImage;
  });

  useEffect(() => {
    const shareToken = sharedImageKey || sharedImageUri;
    if (!shareToken || isLoadingBilling || isAnalyzing) return;
    if (lastProcessedShareToken.current === shareToken) return;
    if (sharedAnalysisInFlightToken.current) return;

    const handoffImageUri = consumeSharedImageUri(sharedImageKey);
    const nextSharedImageUri = handoffImageUri || sharedImageUri;
    if (!nextSharedImageUri) return;

    lastProcessedShareToken.current = shareToken;
    sharedAnalysisInFlightToken.current = shareToken;
    ShareIntentModule?.clearShareIntent(SHARE_INTENT_KEY);

    let cancelled = false;
    (async () => {
      try {
        const analysisUri = await resizeForAnalysisRef.current(nextSharedImageUri);
        if (cancelled || sharedAnalysisInFlightToken.current !== shareToken) return;
        setDemoResultVisible(false);
        setSelectedImage(analysisUri);
        await analyzeImageRef.current(analysisUri, nextSharedImageUri);
      } finally {
        if (sharedAnalysisInFlightToken.current === shareToken) {
          sharedAnalysisInFlightToken.current = null;
        }
      }
    })();

    return () => {
      cancelled = true;
    };
  }, [sharedImageKey, sharedImageUri, isLoadingBilling, isAnalyzing]);

  const takePicture = async () => {
    if (!cameraRef.current || isAnalyzing) return;
    await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
    const photo = await cameraRef.current.takePictureAsync({ base64: false, quality: 0.9 });
    if (photo) {
      const analysisUri = await resizeForAnalysis(photo.uri);
      setDemoResultVisible(false);
      setSelectedImage(analysisUri);
      analyzeImage(analysisUri, photo.uri);
    }
  };

  const pickImage = async () => {
    if (isAnalyzing) return;

    const result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ['images'],
      quality: 1,
      base64: false,
    });
    if (!result.canceled && result.assets[0]) {
      const asset = result.assets[0];
      const analysisUri = await resizeForAnalysis(asset.uri);
      setDemoResultVisible(false);
      setSelectedImage(asset.uri);
      analyzeImage(analysisUri, asset.uri);
    }
  };

  const handleSave = async () => {
    if (analysisResult && selectedImage) {
      if (!session) {
        // Guest mode: store result and go to signup
        setPendingPlant(analysisResult, selectedImage);
        router.replace('/auth/signup');
        return;
      }

      try {
        await savePlant(analysisResult, selectedImage);
        if (router.canGoBack()) {
          router.back();
        } else {
          router.replace('/(tabs)');
        }
      } catch (error) {
        console.error('Saving identified plant failed', error);
        Alert.alert(billingCopy.genericErrorTitle, billingCopy.genericErrorMessage);
      }
    }
  };

  const routeToHardPaywall = () => {
    posthog.capture('auth_prompt_shown', {
      authenticated: Boolean(session),
      surface: 'demo_scan_result',
    });
    if (session) {
      router.replace('/profile/billing');
      return;
    }
    router.replace('/auth/signup');
  };

  const handleDemoAppleSignIn = async () => {
    if (!appleAvailable) {
      routeToHardPaywall();
      return;
    }

    setIsAuthLoading(true);
    posthog.capture('apple_login_started', { surface: 'scanner_demo' });
    try {
      const credential = await AppleAuthentication.signInAsync({
        requestedScopes: [
          AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
          AppleAuthentication.AppleAuthenticationScope.EMAIL,
        ],
      });
      if (!credential.identityToken) {
        throw new Error('APPLE_AUTH_INVALID');
      }
      const fullName = [
        credential.fullName?.givenName,
        credential.fullName?.familyName,
      ].filter(Boolean).join(' ');
      const nextSession = await AuthService.signInWithApple({
        identityToken: credential.identityToken,
        appleUser: credential.user,
        email: credential.email,
        name: fullName || undefined,
      });
      await hydrateSession(nextSession);
      posthog.capture('apple_login_succeeded', { surface: 'scanner_demo' });
      router.replace(nextSession.isNewUser ? '/onboarding/source' : '/(tabs)');
    } catch (error: any) {
      if (error?.code === 'ERR_REQUEST_CANCELED') {
        return;
      }
      posthog.capture('apple_login_failed', {
        surface: 'scanner_demo',
        error: error instanceof Error ? error.message : String(error),
      });
      Alert.alert(
        billingCopy.genericErrorTitle,
        error instanceof Error && error.message === 'APPLE_BACKEND_UNAVAILABLE'
          ? 'Apple Login ist auf dem Backend noch nicht aktiviert. Bitte Backend neu starten oder deployen.'
          : billingCopy.genericErrorMessage,
      );
    } finally {
      setIsAuthLoading(false);
    }
  };

  const handleClose = () => {
    if (router.canGoBack()) {
      router.back();
      return;
    }
    router.replace('/onboarding');
  };

  const controlsPaddingBottom = Math.max(20, insets.bottom + 10);
  const controlsPanelHeight = 28 + 80 + controlsPaddingBottom;
  const analysisBottomOffset = controlsPanelHeight + 12;
  const scanLineTranslateY = scanLineProgress.interpolate({
    inputRange: [0, 1],
    outputRange: [24, 280],
  });
  const scanPulseScale = scanPulse.interpolate({
    inputRange: [0, 1],
    outputRange: [0.98, 1.02],
  });
  const scanPulseOpacity = scanPulse.interpolate({
    inputRange: [0, 1],
    outputRange: [0.22, 0.55],
  });

  // Show result
  if (!isHealthMode && analysisResult && selectedImage) {
    return (
      <ResultCard
        result={analysisResult}
        imageUri={selectedImage}
        onSave={handleSave}
        onClose={handleClose}
        t={t}
        isDark={isDarkMode}
        colorPalette={colorPalette}
        isGuest={!session}
      />
    );
  }

  // Camera permission
  if (!permission?.granted) {
    return (
      <View style={[styles.permissionContainer, { backgroundColor: colors.surface }]}>
        <Ionicons name="camera-outline" size={48} color={colors.text} style={{ marginBottom: 16 }} />
        <Text style={[styles.permissionText, { color: colors.text }]}>Camera access is required to scan plants.</Text>
        <TouchableOpacity style={[styles.permissionBtn, { backgroundColor: colors.primary }]} onPress={requestPermission}>
          <Text style={[styles.permissionBtnText, { color: colors.onPrimary }]}>Continue</Text>
        </TouchableOpacity>
      </View>
    );
  }

  return (
    <View style={[styles.container, { backgroundColor: colors.surface }]}>
      {/* Header */}
      <View style={styles.header}>
        <TouchableOpacity onPress={handleClose}>
          <Ionicons name="close" size={28} color={colors.iconOnImage} />
        </TouchableOpacity>
        <Text style={[styles.headerTitle, { color: colors.iconOnImage }]}>
          {isHealthMode ? billingCopy.healthTitle : t.scanner}
        </Text>
        <View style={[styles.creditBadge, { backgroundColor: colors.heroButton, borderColor: colors.heroButtonBorder }]}>
          <Ionicons name={isDemoMode ? 'sparkles-outline' : 'wallet-outline'} size={12} color={colors.text} />
          <Text style={[styles.creditBadgeText, { color: colors.text }]}>
            {isDemoMode ? billingCopy.demoCreditsRemaining(demoScansRemaining) : `${billingCopy.creditsLabel}: ${availableCredits}`}
          </Text>
        </View>
      </View>

      {/* Camera */}
      <View style={styles.cameraContainer}>
        {selectedImage ? (
          <Image source={{ uri: selectedImage }} style={StyleSheet.absoluteFillObject} blurRadius={4} />
        ) : (
          <CameraView ref={cameraRef} style={StyleSheet.absoluteFillObject} facing="back" />
        )}

        {/* Scan Frame */}
        <View style={[styles.scanFrame, { borderColor: colors.heroButtonBorder }]}>
          {selectedImage && (
            <Image source={{ uri: selectedImage }} style={StyleSheet.absoluteFillObject} resizeMode="cover" />
          )}
          {isAnalyzing && (
            <>
              <Animated.View
                pointerEvents="none"
                style={[
                  styles.scanPulseFrame,
                  {
                    borderColor: colors.heroButton,
                    transform: [{ scale: scanPulseScale }],
                    opacity: scanPulseOpacity,
                  },
                ]}
              />
              <Animated.View
                pointerEvents="none"
                style={[
                  styles.scanLine,
                  {
                    backgroundColor: colors.heroButton,
                    transform: [{ translateY: scanLineTranslateY }],
                  },
                ]}
              />
            </>
          )}
          <View style={[styles.corner, styles.tl, { borderColor: colors.iconOnImage }]} />
          <View style={[styles.corner, styles.tr, { borderColor: colors.iconOnImage }]} />
          <View style={[styles.corner, styles.bl, { borderColor: colors.iconOnImage }]} />
          <View style={[styles.corner, styles.br, { borderColor: colors.iconOnImage }]} />
        </View>
      </View>

      {/* Analyzing Overlay */}
      {isAnalyzing && (
        <View
          style={[
            styles.analysisSheet,
            {
              backgroundColor: colors.overlayStrong,
              borderColor: colors.heroButtonBorder,
              bottom: analysisBottomOffset,
            },
          ]}
        >
          <View style={styles.analysisHeader}>
            <View style={[styles.analysisBadge, { backgroundColor: colors.surfaceMuted }]}>
              <Ionicons name="sparkles-outline" size={12} color={colors.text} />
              <Text style={[styles.analysisLabel, { color: colors.text }]}>
                {analysisProgress < 100 ? t.analyzing : t.result}
              </Text>
            </View>
            <Text style={[styles.analysisPercent, { color: colors.textSecondary }]}>
              {Math.round(analysisProgress)}%
            </Text>
          </View>
          <View style={[styles.progressBg, { backgroundColor: colors.surfaceMuted }]}>
            <View style={[styles.progressFill, { width: `${analysisProgress}%`, backgroundColor: colors.primary }]} />
          </View>
          <View style={styles.analysisFooter}>
            <View style={styles.analysisStatusRow}>
              <View style={[styles.statusDot, { backgroundColor: analysisProgress < 100 ? colors.warning : colors.success }]} />
              <Text style={[styles.analysisStage, { color: colors.textMuted }]}>{t.aiProcessing}</Text>
            </View>
            <Text style={[styles.analysisStageDetail, { color: colors.textSecondary }]}>
              {analysisProgress < 30 ? t.scanStage1 : analysisProgress < 75 ? t.scanStage2 : t.scanStage3}
            </Text>
          </View>
        </View>
      )}

      {demoResultVisible && !isAnalyzing ? (
        <View
          style={[
            styles.demoSheet,
            {
              backgroundColor: colors.background,
              borderColor: colors.border,
              bottom: analysisBottomOffset,
            },
          ]}
        >
          <View style={[styles.demoIconWrap, { backgroundColor: colors.primarySoft }]}>
            <Ionicons name="sparkles" size={22} color={colors.primary} />
          </View>
          <Text style={[styles.demoTitle, { color: colors.text }]}>{billingCopy.demoTitle}</Text>
          <Text style={[styles.demoMessage, { color: colors.textSecondary }]}>{billingCopy.demoMessage}</Text>

          {!session && appleAvailable ? (
            <AppleAuthentication.AppleAuthenticationButton
              buttonType={AppleAuthentication.AppleAuthenticationButtonType.CONTINUE}
              buttonStyle={isDarkMode
                ? AppleAuthentication.AppleAuthenticationButtonStyle.WHITE
                : AppleAuthentication.AppleAuthenticationButtonStyle.BLACK}
              cornerRadius={12}
              style={styles.demoAppleButton}
              onPress={handleDemoAppleSignIn}
            />
          ) : (
            <TouchableOpacity
              style={[styles.demoPrimaryBtn, { backgroundColor: colors.primary }]}
              onPress={session ? routeToHardPaywall : handleDemoAppleSignIn}
              disabled={isAuthLoading}
              activeOpacity={0.85}
            >
              <Text style={[styles.demoPrimaryText, { color: colors.onPrimary }]}>
                {isAuthLoading ? '...' : session ? billingCopy.unlockCta : appleAvailable ? billingCopy.appleCta : billingCopy.emailCta}
              </Text>
            </TouchableOpacity>
          )}

          {!session ? (
            <TouchableOpacity
              style={[styles.demoSecondaryBtn, { borderColor: colors.borderStrong }]}
              onPress={() => {
                posthog.capture('auth_prompt_shown', { surface: 'demo_scan_result', method: 'email' });
                router.replace('/auth/signup');
              }}
              activeOpacity={0.85}
            >
              <Text style={[styles.demoSecondaryText, { color: colors.text }]}>{billingCopy.emailCta}</Text>
            </TouchableOpacity>
          ) : null}
        </View>
      ) : null}

      {/* Bottom Controls */}
      <View
        style={[
          styles.controls,
          {
            backgroundColor: colors.background,
            paddingBottom: controlsPaddingBottom,
          },
        ]}
      >
        <TouchableOpacity style={[styles.controlBtn, isAnalyzing && styles.controlBtnDisabled]} onPress={pickImage} disabled={isAnalyzing}>
          <Ionicons name="images-outline" size={24} color={colors.textSecondary} />
          <Text style={[styles.controlLabel, { color: colors.textMuted }]}>{t.gallery}</Text>
        </TouchableOpacity>

        <TouchableOpacity
          style={[
            styles.shutterBtn,
            { backgroundColor: colors.primary, borderColor: colors.borderStrong },
            isAnalyzing && styles.shutterBtnDisabled,
          ]}
          onPress={takePicture}
          disabled={isAnalyzing}
          activeOpacity={0.7}
        >
          <View style={[styles.shutterInner, { backgroundColor: colors.primarySoft }]} />
        </TouchableOpacity>

        <TouchableOpacity style={[styles.controlBtn, isAnalyzing && styles.controlBtnDisabled]} disabled={isAnalyzing}>
          <Ionicons name="help-circle-outline" size={24} color={colors.textMuted} />
          <Text style={[styles.controlLabel, { color: colors.textMuted }]}>{t.help}</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1 },
  header: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    zIndex: 10,
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    paddingTop: 60,
    paddingHorizontal: 24,
  },
  headerTitle: { fontSize: 18, fontWeight: '600' },
  creditBadge: {
    borderWidth: 1,
    borderRadius: 14,
    paddingHorizontal: 8,
    paddingVertical: 4,
    flexDirection: 'row',
    alignItems: 'center',
    gap: 4,
  },
  creditBadgeText: { fontSize: 10, fontWeight: '700' },
  cameraContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  scanFrame: {
    width: 256,
    height: 320,
    borderWidth: 2.5,
    borderColor: '#ffffff50',
    borderRadius: 28,
    overflow: 'hidden',
  },
  scanPulseFrame: {
    ...StyleSheet.absoluteFillObject,
    borderWidth: 1.5,
    borderRadius: 28,
  },
  scanLine: {
    position: 'absolute',
    left: 16,
    right: 16,
    height: 2,
    borderRadius: 999,
    shadowColor: '#ffffff',
    shadowOffset: { width: 0, height: 0 },
    shadowOpacity: 0.8,
    shadowRadius: 8,
    elevation: 6,
  },
  corner: { position: 'absolute', width: 24, height: 24 },
  tl: { top: 16, left: 16, borderTopWidth: 4, borderLeftWidth: 4, borderTopLeftRadius: 12 },
  tr: { top: 16, right: 16, borderTopWidth: 4, borderRightWidth: 4, borderTopRightRadius: 12 },
  bl: { bottom: 16, left: 16, borderBottomWidth: 4, borderLeftWidth: 4, borderBottomLeftRadius: 12 },
  br: { bottom: 16, right: 16, borderBottomWidth: 4, borderRightWidth: 4, borderBottomRightRadius: 12 },
  controls: {
    borderTopLeftRadius: 28,
    borderTopRightRadius: 28,
    paddingHorizontal: 32,
    paddingTop: 28,
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
  },
  controlBtn: { alignItems: 'center', gap: 6 },
  controlBtnDisabled: { opacity: 0.5 },
  controlLabel: { fontSize: 11, fontWeight: '500' },
  shutterBtn: {
    width: 80,
    height: 80,
    borderRadius: 40,
    borderWidth: 4,
    justifyContent: 'center',
    alignItems: 'center',
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 4 },
    shadowOpacity: 0.2,
    shadowRadius: 8,
    elevation: 8,
  },
  shutterInner: { width: 64, height: 64, borderRadius: 32 },
  shutterBtnDisabled: { opacity: 0.6 },
  analysisSheet: {
    position: 'absolute',
    left: 16,
    right: 16,
    borderRadius: 20,
    borderWidth: 1,
    paddingHorizontal: 16,
    paddingVertical: 14,
    zIndex: 20,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 4 },
    shadowOpacity: 0.28,
    shadowRadius: 14,
    elevation: 14,
  },
  demoSheet: {
    position: 'absolute',
    left: 16,
    right: 16,
    borderRadius: 22,
    borderWidth: 1,
    padding: 18,
    zIndex: 25,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 4 },
    shadowOpacity: 0.24,
    shadowRadius: 12,
    elevation: 12,
  },
  demoIconWrap: {
    width: 42,
    height: 42,
    borderRadius: 21,
    justifyContent: 'center',
    alignItems: 'center',
    marginBottom: 10,
  },
  demoTitle: {
    fontSize: 20,
    fontWeight: '800',
    marginBottom: 6,
  },
  demoMessage: {
    fontSize: 14,
    lineHeight: 20,
    marginBottom: 14,
  },
  demoAppleButton: {
    width: '100%',
    height: 50,
    marginBottom: 10,
  },
  demoPrimaryBtn: {
    height: 50,
    borderRadius: 12,
    alignItems: 'center',
    justifyContent: 'center',
    marginBottom: 10,
  },
  demoPrimaryText: {
    fontSize: 15,
    fontWeight: '800',
  },
  demoSecondaryBtn: {
    height: 48,
    borderRadius: 12,
    borderWidth: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  demoSecondaryText: {
    fontSize: 14,
    fontWeight: '700',
  },
  analysisHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 },
  analysisBadge: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 6,
    borderRadius: 999,
    paddingHorizontal: 10,
    paddingVertical: 5,
  },
  analysisLabel: { fontWeight: '700', fontSize: 12, letterSpacing: 0.2 },
  analysisPercent: { fontFamily: 'monospace', fontSize: 12, fontWeight: '700' },
  progressBg: { height: 9, borderRadius: 999, overflow: 'hidden', marginBottom: 10 },
  progressFill: { height: '100%', borderRadius: 4 },
  analysisFooter: { gap: 4 },
  analysisStatusRow: { flexDirection: 'row', alignItems: 'center', gap: 6 },
  statusDot: { width: 8, height: 8, borderRadius: 4 },
  analysisStage: { fontSize: 10, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 1 },
  analysisStageDetail: { fontSize: 11, lineHeight: 16, fontWeight: '500' },
  permissionContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 32 },
  permissionText: { fontSize: 16, textAlign: 'center', marginBottom: 20 },
  permissionBtn: { paddingHorizontal: 24, paddingVertical: 12, borderRadius: 12 },
  permissionBtnText: { fontWeight: '700', fontSize: 15 },
});
