// Full-screen overlay shown while an EAS Update downloads and applies.
//
// It exists because of what expo-updates does by DEFAULT, which is nothing
// visible. `fallbackToCacheTimeout: 0` means the app launches from the cached
// bundle immediately, fetches any new update in the background, and applies it
// on the NEXT cold start — so a tester relaunches once, sees the old build,
// relaunches again, and sees the new one. Every app here reacts to the pending
// update by reloading straight away instead; this component is what turns the
// resulting pause into a visible, explained wait rather than the app appearing
// to hang.
//
// # Why this is in the shared package
//
// It was written in vault, ported by hand into wheatley and glados, and then
// FIXED in the ports while vault kept the bug (see the colour note below).
// Three copies, one of which was wrong, of a component whose entire job is to
// render correctly in the worst conditions the app ever has. Sharing it is how
// the next fix reaches all three.
//
// # Every colour is a literal, and that is the fix
//
// This renders while the app is NOT ready — during a cold start whose update
// is still downloading, and during the reload that applies it. NativeWind's
// `dark:` variant and theme tokens like `text-foreground` only resolve once the
// provider tree has mounted and run its effects, which by definition has not
// happened yet. Asking the theme produced light-mode ink on a dark ground: an
// invisible label on what the user reads as a black screen. Observed for real
// on Android in both wheatley (2026-08-23) and vault (2026-08-29).
//
// The values ARE the palettes' own — this matches the theme, it just does not
// ask it. An overlay whose whole job is to render before the app is ready
// cannot depend on app state to be legible.
//
// reanimated rather than RN's `Animated`, matching the animation convention in
// every consumer.
import * as React from "react";
import { StyleSheet, Text, View, useColorScheme } from "react-native";
import Animated, { Easing, useAnimatedStyle, useSharedValue, withRepeat, withTiming, } from "react-native-reanimated";
import { EntropyMark } from "./entropy-mark";
/** How long one full turn takes. Slow enough to read as deliberate, fast
 *  enough to look like work rather than a frozen frame. */
const SPIN_MS = 1100;
const PALETTE = {
    dark: {
        ground: "#000000",
        ink: "#EBEFEB",
        muted: "#A3A3A3",
        track: "#262626",
        arc: "#FFFFFF",
    },
    light: {
        ground: "#FFFFFF",
        ink: "#0A0A0A",
        muted: "#737373",
        track: "#E5E5E5",
        arc: "#000000",
    },
};
export function UpdateOverlay({ phase, progress, mark, scheme, background, downloadingLabel = "Installing update…", restartingLabel = "Restarting…", }) {
    // RN's own hook, not NativeWind's: this has to work before the NativeWind
    // provider has done anything, which is the entire premise of the component.
    const system = useColorScheme();
    const isDark = (scheme ?? system) !== "light";
    const c = isDark ? PALETTE.dark : PALETTE.light;
    const rotation = useSharedValue(0);
    // Started on mount rather than gated on a `visible` prop: the caller renders
    // this conditionally, so mounting IS becoming visible, and a prop would be a
    // second source of truth for the same fact.
    React.useEffect(() => {
        rotation.value = withRepeat(withTiming(360, { duration: SPIN_MS, easing: Easing.linear }), -1, false);
    }, [rotation]);
    const ringStyle = useAnimatedStyle(() => ({
        transform: [{ rotate: `${rotation.value}deg` }],
    }));
    return (<View style={[StyleSheet.absoluteFill, styles.ground, { backgroundColor: background ?? c.ground }]} 
    // Announced as one modal thing rather than as its parts: a screen reader
    // reading "Installing update" then "43%" as separate nodes during a
    // two-second wait is noise, and the percentage is decoration on top of
    // the label rather than information of its own.
    accessibilityViewIsModal accessibilityLabel={phase === "downloading" ? downloadingLabel : restartingLabel}>
      <View style={styles.markWell}>
        <Animated.View style={[
            ringStyle,
            styles.ring,
            // The track, then one lit arc. A single contrasting border-top is
            // what makes a plain rotation read as a spinner — a uniform ring
            // rotating is indistinguishable from a static one.
            { borderColor: c.track, borderTopColor: c.arc },
        ]}/>
        {mark ?? <EntropyMark size={32} variant="chroma"/>}
      </View>
      <Text style={[styles.label, { color: c.ink }]}>
        {phase === "downloading" ? downloadingLabel : restartingLabel}
      </Text>
      {phase === "downloading" && typeof progress === "number" ? (<Text style={[styles.progress, { color: c.muted }]}>{Math.round(progress * 100)}%</Text>) : null}
    </View>);
}
// StyleSheet rather than className throughout, deliberately: NativeWind classes
// resolve through the same provider this component cannot wait for. Plain RN
// styles are the only thing guaranteed to apply here. The ring also needs
// concrete numbers that agree with each other (a 72px box, a 36px radius, one
// 3px border), and its transform comes from an animated style anyway.
const styles = StyleSheet.create({
    ground: {
        alignItems: "center",
        justifyContent: "center",
        // Both, not either: zIndex orders within the JS view hierarchy and
        // elevation is what Android's native compositor honours. A high zIndex
        // alone can still be drawn under an elevated sibling.
        zIndex: 10000,
        elevation: 10000,
    },
    markWell: {
        width: 72,
        height: 72,
        alignItems: "center",
        justifyContent: "center",
    },
    ring: {
        position: "absolute",
        width: 72,
        height: 72,
        borderRadius: 36,
        borderWidth: 3,
    },
    // No font family: the overlay can render before the app's fonts have loaded,
    // and naming one that is not there yet gives a blank label rather than a
    // system-font fallback.
    label: { marginTop: 20, fontSize: 16, fontWeight: "500" },
    progress: { marginTop: 4, fontSize: 12 },
});
//# sourceMappingURL=update-overlay.jsx.map