import React, { useEffect, useRef, useState } from "react";
import {
  Animated,
  Easing,
  Image,
  StyleSheet,
  Text,
  View,
} from "react-native";
import { StatusBar } from "expo-status-bar";
import * as Updates from "expo-updates";

type Phase = "checking" | "downloading" | "ready";

// Duree minimale d'affichage de l'ecran pendant qu'une mise a jour est posee,
// pour qu'il soit lisible meme quand le telechargement est instantane. Ne
// s'applique PAS au cas "pas d'update" (ouverture rapide preservee).
const UPDATE_MIN_VISIBLE_MS = 1600;

/**
 * Porte de demarrage : verifie une mise a jour OTA (expo-updates) AVANT
 * d'afficher l'app, telecharge si dispo puis recharge l'app sur le nouveau
 * bundle. Evite le cycle "ouvrir / fermer / rouvrir" : la nouvelle version est
 * appliquee des le premier lancement.
 *
 * - En dev / Expo Go (`Updates.isEnabled` false ou `__DEV__`) : on saute la
 *   verif et on affiche l'app immediatement (les OTA n'existent pas en dev).
 * - Aucune update / hors-ligne / erreur : on continue sans bloquer.
 * - Garde-fou : on ne bloque jamais l'ouverture plus de 8 s (reseau pendu).
 */
export default function UpdateGate({
  children,
}: Readonly<{ children: React.ReactNode }>) {
  const [phase, setPhase] = useState<Phase>(() =>
    Updates.isEnabled && !__DEV__ ? "checking" : "ready"
  );

  useEffect(() => {
    if (phase === "ready") {
      return;
    }
    let active = true;
    let safety: ReturnType<typeof setTimeout>;
    // Horodatage du moment ou la phase "downloading" commence : sert a garantir
    // une duree minimale d'affichage de l'ecran de mise a jour (sinon, sur bon
    // reseau, le telechargement est si rapide que l'ecran passe en un flash).
    let downloadStartedAt = 0;

    const waitMinVisible = async () => {
      const elapsed = Date.now() - downloadStartedAt;
      const remaining = UPDATE_MIN_VISIBLE_MS - elapsed;
      if (remaining > 0) {
        await new Promise((resolve) => setTimeout(resolve, remaining));
      }
    };

    const run = async () => {
      try {
        const result = await Updates.checkForUpdateAsync();
        if (!active) {
          return;
        }
        if (result.isAvailable) {
          // Update trouvee : on s'engage a la poser -> on annule le garde-fou
          // pour ne pas afficher l'app puis la recharger brutalement.
          clearTimeout(safety);
          downloadStartedAt = Date.now();
          setPhase("downloading");
          await Updates.fetchUpdateAsync();
          // Laisse l'ecran "Mise a jour en cours" visible un minimum lisible
          // avant de recharger, meme si le download a ete instantane.
          await waitMinVisible();
          if (!active) {
            return;
          }
          // Redemarre l'app sur le nouveau bundle (ne revient jamais ici).
          await Updates.reloadAsync();
          return;
        }
      } catch {
        // Hors-ligne, pas d'update, ou updates indispo : on continue vers l'app.
      }
      // Cas "pas d'update" : on n'impose PAS de delai -> ouverture rapide.
      clearTimeout(safety);
      if (active) {
        setPhase("ready");
      }
    };

    safety = setTimeout(() => {
      if (active) {
        setPhase("ready");
      }
    }, 8000);

    void run();

    return () => {
      active = false;
      clearTimeout(safety);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  if (phase === "ready") {
    return <>{children}</>;
  }

  return <UpdateSplash downloading={phase === "downloading"} />;
}

function UpdateSplash({ downloading }: Readonly<{ downloading: boolean }>) {
  // Barre de progression indeterminee : le JS API d'expo-updates n'expose pas
  // d'evenement de progression, donc on anime une barre qui glisse en boucle.
  const slide = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    const loop = Animated.loop(
      Animated.timing(slide, {
        toValue: 1,
        duration: 1100,
        easing: Easing.inOut(Easing.ease),
        useNativeDriver: true,
      })
    );
    loop.start();
    return () => loop.stop();
  }, [slide]);

  const translateX = slide.interpolate({
    inputRange: [0, 1],
    outputRange: [-BAR_WIDTH, TRACK_WIDTH],
  });

  return (
    <View style={styles.root}>
      <StatusBar style="light" />
      <View style={styles.card}>
        <Image
          source={require("../../../assets/icon.png")}
          style={styles.logo}
          resizeMode="contain"
        />
        <Text style={styles.appName}>MissioFlow</Text>
        <Text style={styles.title}>
          {downloading ? "Mise à jour en cours" : "Recherche de mises à jour"}
        </Text>
        <Text style={styles.subtitle}>
          {downloading
            ? "Téléchargement de la dernière version…"
            : "Vérification de la dernière version…"}
        </Text>
        <View style={styles.track}>
          <Animated.View style={[styles.bar, { transform: [{ translateX }] }]} />
        </View>
      </View>
      <Text style={styles.footer}>Quelques secondes…</Text>
    </View>
  );
}

const TRACK_WIDTH = 190;
const BAR_WIDTH = 72;

const styles = StyleSheet.create({
  root: {
    flex: 1,
    backgroundColor: "#0b2a6b",
    justifyContent: "center",
    alignItems: "center",
    padding: 24,
  },
  card: {
    width: 290,
    alignItems: "center",
    paddingVertical: 30,
    paddingHorizontal: 24,
    borderRadius: 22,
    backgroundColor: "rgba(255,255,255,0.06)",
    borderWidth: 1,
    borderColor: "rgba(255,255,255,0.12)",
  },
  logo: {
    width: 76,
    height: 76,
    borderRadius: 20,
    marginBottom: 14,
  },
  appName: {
    color: "#ffffff",
    fontSize: 21,
    fontWeight: "800",
    letterSpacing: 0.5,
  },
  title: {
    color: "#ffffff",
    fontSize: 16,
    fontWeight: "700",
    marginTop: 16,
  },
  subtitle: {
    color: "#c7d6f5",
    fontSize: 13,
    marginTop: 6,
    textAlign: "center",
  },
  track: {
    width: TRACK_WIDTH,
    height: 5,
    borderRadius: 3,
    backgroundColor: "rgba(255,255,255,0.16)",
    overflow: "hidden",
    marginTop: 22,
  },
  bar: {
    width: BAR_WIDTH,
    height: 5,
    borderRadius: 3,
    backgroundColor: "#60a5fa",
  },
  footer: {
    color: "#93b0e6",
    fontSize: 12,
    marginTop: 26,
  },
});
