import React, { useEffect, useState } from "react";
import { Pressable, View } from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { useColorScheme } from "nativewind";
import { MutedText, Text } from "./text";
import { copyToClipboard } from "../utils/clipboard";
const PLACEHOLDER = "------";
/**
 * TOTP code display with a circular countdown ring. Recomputes the code
 * on each 30s window boundary; ticks the remaining-seconds value once
 * per second to drive the ring animation.
 */
export function TotpDisplay({ secret, computeCode, period = 30, onCopy, }) {
    const { colorScheme } = useColorScheme();
    const isDark = colorScheme === "dark";
    const safeCompute = (s) => {
        if (!s) {
            return PLACEHOLDER;
        }
        try {
            return computeCode(s);
        }
        catch {
            return PLACEHOLDER;
        }
    };
    const [code, setCode] = useState(() => safeCompute(secret));
    const [remaining, setRemaining] = useState(() => {
        const now = Math.floor(Date.now() / 1000);
        return period - (now % period);
    });
    useEffect(() => {
        if (!secret) {
            return;
        }
        let lastWindow = -1;
        const tick = () => {
            const now = Math.floor(Date.now() / 1000);
            const window = Math.floor(now / period);
            setRemaining(period - (now % period));
            if (window !== lastWindow) {
                lastWindow = window;
                setCode(safeCompute(secret));
            }
        };
        tick();
        const id = setInterval(tick, 1000);
        return () => clearInterval(id);
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [secret, period]);
    if (!secret) {
        return null;
    }
    const copy = async () => {
        if (!code || code === PLACEHOLDER) {
            return;
        }
        // Route through the shared helper so the 30s auto-clear applies.
        // TOTP codes rotate every 30s anyway, but the clipboard residue
        // still leaks the code to whatever the user pastes next (or to
        // a shoulder-surfer hitting paste).
        const ok = await copyToClipboard(code);
        if (ok) {
            onCopy?.(code);
        }
    };
    const urgent = remaining <= 5;
    const foreground = isDark ? "rgb(255, 255, 255)" : "rgb(0, 0, 0)";
    const destructive = "rgb(239, 68, 68)";
    const border = isDark ? "rgb(38, 38, 38)" : "rgb(229, 229, 229)";
    const card = isDark ? "rgb(0, 0, 0)" : "rgb(255, 255, 255)";
    const secondary = isDark ? "rgb(38, 38, 38)" : "rgb(245, 245, 245)";
    const accent = urgent ? destructive : foreground;
    return (<Pressable onPress={copy} accessibilityRole="button" accessibilityLabel="Copy TOTP code" accessibilityHint="Copies the current one-time code to the clipboard" style={({ pressed }) => ({
            flexDirection: "row",
            alignItems: "center",
            gap: 12,
            padding: 12,
            borderRadius: 8,
            borderWidth: 1,
            borderColor: border,
            backgroundColor: pressed ? secondary : card,
        })}>
      <CountdownRing remaining={remaining} total={period} color={accent} backgroundColor={border}/>
      <View style={{ flex: 1 }}>
        <MutedText className="text-xs" style={{ marginBottom: 2 }}>
          TOTP code
        </MutedText>
        <Text style={{
            color: accent,
            fontSize: 22,
            fontWeight: "600",
            letterSpacing: 4,
            fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
        }}>
          {`${code.slice(0, 3)} ${code.slice(3)}`}
        </Text>
      </View>
      <Ionicons name="copy-outline" size={16} color={isDark ? "rgb(163, 163, 163)" : "rgb(115, 115, 115)"}/>
    </Pressable>);
}
function CountdownRing({ remaining, total, color, backgroundColor }) {
    const size = 36;
    const stroke = 3;
    const radius = (size - stroke) / 2;
    const circumference = 2 * Math.PI * radius;
    const fraction = Math.max(0, Math.min(1, remaining / total));
    const dashOffset = circumference * (1 - fraction);
    // Cast raw SVG tags through React.createElement so RN-Web renders them
    // as real <svg> / <circle> elements without depending on
    // `react-native-svg`. Native targets fall back to the View at the
    // outer level — apps that want native parity should overlay this with
    // an SVG-backed implementation in their own component layer.
    const Svg = "svg";
    const Circle = "circle";
    return (<View style={{ width: size, height: size, alignItems: "center", justifyContent: "center" }}>
      <Svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
        <Circle cx={size / 2} cy={size / 2} r={radius} fill="none" stroke={backgroundColor} strokeWidth={stroke}/>
        <Circle cx={size / 2} cy={size / 2} r={radius} fill="none" stroke={color} strokeWidth={stroke} strokeLinecap="round" strokeDasharray={circumference} strokeDashoffset={dashOffset} transform={`rotate(-90 ${size / 2} ${size / 2})`} style={{ transition: "stroke-dashoffset 1s linear" }}/>
      </Svg>
      <Text style={{
            position: "absolute",
            color,
            fontSize: 11,
            fontWeight: "600",
            fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
        }}>
        {remaining}
      </Text>
    </View>);
}
//# sourceMappingURL=totp-display.jsx.map