import { useEffect, useState } from 'react';
import { View, Text, Platform } from 'react-native';
import { Asset } from 'expo-asset';
import Rive, { Fit, Alignment } from 'rive-react-native';

// Android: Rive akzeptiert NUR raw-resource oder url, kein file:// uri.
// Asset liegt als android/app/src/main/res/raw/lyra_avatar.riv (gebundelt
// via plugins/with-rive-asset-android.js). resourceName = filename ohne
// extension, lowercase + underscores (Android raw-resource convention).
const ANDROID_RIVE_RESOURCE = 'lyra_avatar';

// Modul-Level: nur EINMAL die Asset registrieren + URI cachen.
// In Production-Builds wird die .riv ins App-Bundle gebakt (Asset.localUri
// zeigt sofort auf das Bundle-File). In Dev-Builds wird sie beim ersten Mal
// von Metro gezogen + ins App-Sandbox-Cache geschrieben — danach offline.
const RIVE_MODULE = require('../assets/lyra-avatar.riv');
let cachedRiveUri: string | null = null;
let preloadPromise: Promise<string | null> | null = null;

function preloadRiveAsset(): Promise<string | null> {
  if (cachedRiveUri) return Promise.resolve(cachedRiveUri);
  if (preloadPromise) return preloadPromise;
  preloadPromise = Asset.fromModule(RIVE_MODULE)
    .downloadAsync()
    .then((asset) => {
      const uri = asset.localUri ?? asset.uri;
      cachedRiveUri = uri;
      return uri;
    })
    .catch((err) => {
      console.warn('[RiveAvatar] preload failed:', err?.message ?? err);
      preloadPromise = null;
      return null;
    });
  return preloadPromise;
}

// Kicke den Preload sofort beim Modul-Import an — damit der erste
// Render bereits die cached URI nutzt (außer im allerersten App-Start).
preloadRiveAsset();

// Supported emotions sind durch state-machine im .riv-file definiert.
// Neue states: nur EMOTION_ANIMATIONS + EMOTION_LABELS erweitern, kein weiterer Code-Change nötig.
export type SupportedEmotion = 'idle' | 'happy' | 'thinking' | 'empathy';
export type Emotion = SupportedEmotion | (string & {});

// Direkte Animation-Namen aus der .riv-Datei (1:1 mit Nuxt BenAvatar.vue).
// "happy" hat zwei Phasen: erst Übergangs-Animation, dann Loop.
const EMOTION_ANIMATIONS: Record<string, string> = {
  idle: 'Idle Loop',
  happy: 'idle to Pose 1',
  thinking: 'WALK',
  empathy: '01 Wave 1',
};

const EMOTION_LABELS: Record<string, string> = {
  idle: 'bereit',
  happy: 'froh für dich',
  thinking: 'überlegt ...',
  empathy: 'versteht dich',
};

const SIZE_PX: Record<'sm' | 'md' | 'lg', number> = {
  sm: 40,
  md: 112,
  lg: 160,
};

type Props = {
  emotion: Emotion;
  size?: 'sm' | 'md' | 'lg';
  showLabel?: boolean;
  fallback?: Emotion;
};

export function RiveAvatar({ emotion, size = 'md', showLabel = false, fallback = 'idle' }: Props) {
  const px = SIZE_PX[size];

  const resolvedEmotion = EMOTION_ANIMATIONS[emotion] !== undefined ? emotion : fallback;

  // Aktuelle Animation als deklarativer State (kein imperatives ref.play()).
  const [currentAnim, setCurrentAnim] = useState<string>(EMOTION_ANIMATIONS[resolvedEmotion] ?? EMOTION_ANIMATIONS.idle);

  // Lokale URI für die .riv-Datei — geht über expo-asset damit der File
  // im App-Sandbox gecached wird statt jedes Mal von Metro zu streamen.
  // Nach erstem Load funktioniert's auch komplett offline.
  const [riveUri, setRiveUri] = useState<string | null>(cachedRiveUri);

  useEffect(() => {
    if (riveUri) return; // schon gecached
    let active = true;
    preloadRiveAsset().then((uri) => {
      if (active && uri) setRiveUri(uri);
    });
    return () => {
      active = false;
    };
  }, [riveUri]);

  useEffect(() => {
    if (resolvedEmotion === 'happy') {
      // 2-Phasen-Flow: Übergang (~900ms) → Loop (1:1 wie Nuxt-BenAvatar)
      setCurrentAnim('idle to Pose 1');
      const t = setTimeout(() => setCurrentAnim('Pose 1 loop'), 900);
      return () => clearTimeout(t);
    }
    setCurrentAnim(EMOTION_ANIMATIONS[resolvedEmotion] ?? EMOTION_ANIMATIONS.idle);
  }, [resolvedEmotion]);

  return (
    <View style={{ alignItems: 'center', gap: 4 }}>
      <View
        style={{
          width: px,
          height: px,
          // Floating-Shadow nur für md/lg — bei sm zu klein, würde unsauber wirken
          ...(size !== 'sm' && {
            shadowColor: '#000',
            shadowOffset: { width: 0, height: 8 },
            shadowOpacity: 0.18,
            shadowRadius: 16,
            elevation: 10,
          }),
        }}
      >
        <View
          style={{
            width: px,
            height: px,
            borderRadius: px / 2,
            overflow: 'hidden',
            backgroundColor: '#ffffff',
            borderWidth: size !== 'sm' ? 4 : 0,
            borderColor: '#ffffff',
          }}
        >
          {Platform.OS === 'android' ? (
            // Android: Bundle-Resource direkt (kein expo-asset Preload nötig)
            <Rive
              key={currentAnim}
              resourceName={ANDROID_RIVE_RESOURCE}
              autoplay
              animationName={currentAnim}
              fit={Fit.Cover}
              alignment={Alignment.Center}
              style={{ width: px, height: px }}
            />
          ) : riveUri ? (
            // iOS: file:// URI aus expo-asset Cache funktioniert
            <Rive
              key={currentAnim}
              source={{ uri: riveUri }}
              autoplay
              animationName={currentAnim}
              fit={Fit.Cover}
              alignment={Alignment.Center}
              style={{ width: px, height: px }}
            />
          ) : (
            <View style={{ width: px, height: px, backgroundColor: '#ffffff' }} />
          )}
        </View>
      </View>

      {showLabel && (
        <Text style={{ fontSize: 11, color: '#737373', letterSpacing: 0.3 }}>
          {EMOTION_LABELS[resolvedEmotion] ?? EMOTION_LABELS[fallback] ?? ''}
        </Text>
      )}
    </View>
  );
}
