import React, { useEffect, useRef, useState } from "react";
import { ActivityIndicator, Modal, Pressable, ScrollView, Text, useWindowDimensions, View, } from "react-native";
import { Gesture, GestureDetector, GestureHandlerRootView } from "react-native-gesture-handler";
import Animated, { FadeIn, FadeOut, useAnimatedStyle, useSharedValue, withTiming, } from "react-native-reanimated";
import { Check, ChevronDown, GripHorizontal, X } from "lucide-react-native";
import { Button } from "./button";
import { Input } from "./input";
import { usePalette } from "../utils/palette";
const SUCCESS = "#16a34a";
function normalizeCustom(input) {
    const v = input.trim().replace(/\/+$/, "");
    if (!v) {
        return "";
    }
    return /^https?:\/\//i.test(v) ? v : `https://${v}`;
}
const defaultValidate = (body) => {
    const s = body?.status;
    return s === "ok" || s === "healthy";
};
/**
 * Connection dialog — a faithful port of simple-finance's, themed from the
 * palette (so it tracks the active theme instead of hard-coded brand colors)
 * and upstreamed here so both apps share one implementation. Draggable card
 * (grip header, double-tap to recenter), Standalone/Cloud mode pills, a
 * server dropdown (Entropy-hosted or self-hosted), and a live debounced
 * health check. Standalone is gated until its backend lands.
 */
export function ConnectionSettings({ visible, onClose, mode, serverUrl, onSave, entropyUrl, healthPath = "/health", validateHealth = defaultValidate, allowStandalone = false, }) {
    const { palette: p } = usePalette();
    const [localMode, setLocalMode] = useState(mode);
    const [endpoint, setEndpoint] = useState(serverUrl && serverUrl !== entropyUrl ? "custom" : "entropy");
    const [custom, setCustom] = useState(serverUrl && serverUrl !== entropyUrl ? serverUrl : "");
    const [open, setOpen] = useState(false);
    const [test, setTest] = useState("idle");
    const [testMsg, setTestMsg] = useState("");
    // Re-sync to props whenever the dialog opens.
    useEffect(() => {
        if (!visible) {
            return;
        }
        setLocalMode(mode);
        setEndpoint(serverUrl && serverUrl !== entropyUrl ? "custom" : "entropy");
        setCustom(serverUrl && serverUrl !== entropyUrl ? serverUrl : "");
        setOpen(false);
        setTest("idle");
        setTestMsg("");
    }, [visible, mode, serverUrl, entropyUrl]);
    // Dropdown is rendered as the card's last child (so it always paints on
    // top); we measure the selector to anchor it.
    const cardRef = useRef(null);
    const selRef = useRef(null);
    const [menu, setMenu] = useState(null);
    const toggleMenu = () => {
        if (open) {
            setOpen(false);
            return;
        }
        selRef.current?.measureInWindow((x, y, w, h) => {
            cardRef.current?.measureInWindow((cx, cy) => {
                setMenu({ top: y - cy + h + 6, left: x - cx, width: w });
                setOpen(true);
            });
        });
    };
    // ── Draggable card, clamped to stay on screen ──────────────────────────────
    const win = useWindowDimensions();
    const tx = useSharedValue(0);
    const ty = useSharedValue(0);
    const startX = useSharedValue(0);
    const startY = useSharedValue(0);
    const cardW = useSharedValue(0);
    const cardH = useSharedValue(0);
    useEffect(() => {
        if (visible) {
            tx.value = 0;
            ty.value = 0;
        }
    }, [visible, tx, ty]);
    const drag = Gesture.Pan()
        .onBegin(() => {
        startX.value = tx.value;
        startY.value = ty.value;
    })
        .onUpdate((e) => {
        const maxX = Math.max(0, (win.width - cardW.value) / 2 - 8);
        const maxY = Math.max(0, (win.height - cardH.value) / 2 - 8);
        tx.value = Math.min(maxX, Math.max(-maxX, startX.value + e.translationX));
        ty.value = Math.min(maxY, Math.max(-maxY, startY.value + e.translationY));
    });
    const recenter = Gesture.Tap()
        .numberOfTaps(2)
        .onEnd(() => {
        tx.value = withTiming(0, { duration: 220 });
        ty.value = withTiming(0, { duration: 220 });
    });
    const handleGesture = Gesture.Race(drag, recenter);
    const dragStyle = useAnimatedStyle(() => ({
        transform: [{ translateX: tx.value }, { translateY: ty.value }],
    }));
    const resolvedUrl = endpoint === "entropy" ? entropyUrl : normalizeCustom(custom);
    const runTest = async (url) => {
        if (!url) {
            setTest("fail");
            setTestMsg("Enter a server address");
            return;
        }
        setTest("testing");
        setTestMsg("");
        try {
            const res = await fetch(`${url}${healthPath}`, { method: "GET" });
            const body = (await res.json().catch(() => ({})));
            if (res.ok && validateHealth(body)) {
                setTest("ok");
                setTestMsg("Connected");
            }
            else {
                setTest("fail");
                setTestMsg(`Responded ${res.status}`);
            }
        }
        catch (e) {
            setTest("fail");
            setTestMsg(e instanceof Error ? e.message : "Could not reach server");
        }
    };
    const canSave = localMode === "standalone" || test === "ok";
    // Auto-test (debounced) whenever the cloud endpoint changes.
    useEffect(() => {
        if (!visible || localMode !== "cloud") {
            return;
        }
        if (!resolvedUrl) {
            setTest("idle");
            return;
        }
        const h = setTimeout(() => void runTest(resolvedUrl), 500);
        return () => clearTimeout(h);
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [visible, localMode, endpoint, custom, resolvedUrl]);
    return (<Modal visible={visible} transparent animationType="none" onRequestClose={onClose} statusBarTranslucent>
      <GestureHandlerRootView style={{ flex: 1 }}>
        <Animated.View entering={FadeIn.duration(160)} exiting={FadeOut.duration(120)} style={{ flex: 1 }}>
          <Pressable style={{
            flex: 1,
            backgroundColor: "#000000B0",
            alignItems: "center",
            justifyContent: "center",
            padding: 24,
        }} onPress={onClose}>
            <Animated.View entering={FadeIn.duration(180)} onLayout={(e) => {
            cardW.value = e.nativeEvent.layout.width;
            cardH.value = e.nativeEvent.layout.height;
        }} style={[{ width: "100%", maxWidth: 520 }, dragStyle]}>
              <Pressable ref={cardRef} onPress={(e) => e.stopPropagation()} style={{
            backgroundColor: p.popover,
            borderRadius: 24,
            borderColor: p.border,
            borderWidth: 1,
            paddingHorizontal: 22,
            paddingBottom: 22,
            paddingTop: 10,
            gap: 16,
        }}>
                {/* drag handle: whole header bar drags; double-tap recenters */}
                <GestureDetector gesture={handleGesture}>
                  <View style={{
            marginHorizontal: -22,
            paddingHorizontal: 22,
            userSelect: "none",
        }}>
                    <View style={{ alignItems: "center", paddingVertical: 4 }}>
                      <GripHorizontal size={20} color={p.mutedForeground}/>
                    </View>
                    <View style={{
            flexDirection: "row",
            alignItems: "center",
            justifyContent: "space-between",
        }}>
                      <Text style={{ color: p.foreground, fontSize: 18, fontWeight: "700" }}>
                        Connection
                      </Text>
                      <Pressable onPress={onClose} hitSlop={10} style={{ padding: 4 }}>
                        <X size={20} color={p.mutedForeground}/>
                      </Pressable>
                    </View>
                  </View>
                </GestureDetector>

                <ScrollView style={{ maxHeight: win.height * 0.66 }} contentContainerStyle={{ gap: 16 }} keyboardShouldPersistTaps="handled" showsVerticalScrollIndicator={false}>
                  {/* mode segmented */}
                  <View style={{
            backgroundColor: p.muted,
            borderRadius: 14,
            padding: 4,
            flexDirection: "row",
            gap: 4,
        }}>
                    <ModePill label="Cloud" active={localMode === "cloud"} onPress={() => setLocalMode("cloud")} palette={p}/>
                    <ModePill label="Standalone" active={localMode === "standalone"} disabled={!allowStandalone} onPress={() => setLocalMode("standalone")} palette={p}/>
                  </View>

                  {localMode === "standalone" ? (<Text style={{ color: p.mutedForeground, fontSize: 13, lineHeight: 19 }}>
                      {allowStandalone
                ? "Private by default. Your vault stays on this device — no account, no server."
                : "On-device, account-free mode is coming soon. For now, sign in to your Entropy or self-hosted server."}
                    </Text>) : (<View style={{ gap: 12 }}>
                      <Text style={{ color: p.mutedForeground, fontSize: 13, lineHeight: 19 }}>
                        Sign in to sync across devices. Use Entropy&apos;s hosted server or point at
                        one you run yourself.
                      </Text>

                      {/* endpoint selector — dropdown floats as an overlay so the
                dialog never resizes when it opens. */}
                      <View style={{ position: "relative", zIndex: open ? 100 : 1 }}>
                        <Text style={{
                color: p.mutedForeground,
                fontSize: 13,
                fontWeight: "500",
                marginBottom: 6,
            }}>
                          Server
                        </Text>
                        <Pressable ref={selRef} onPress={toggleMenu} style={{
                height: 52,
                borderRadius: 14,
                backgroundColor: p.background,
                borderWidth: 1,
                borderColor: open ? p.primary : p.border,
                flexDirection: "row",
                alignItems: "center",
                paddingHorizontal: 14,
            }}>
                          <View style={{ flex: 1 }}>
                            <Text style={{ color: p.foreground, fontSize: 15, fontWeight: "500" }}>
                              {endpoint === "entropy" ? "Entropy Cloud" : "Custom server"}
                            </Text>
                            <Text style={{ color: p.mutedForeground, fontSize: 11, marginTop: 1 }}>
                              {endpoint === "entropy" ? entropyUrl : "DNS / IP / host:port"}
                            </Text>
                          </View>
                          <Animated.View style={{ transform: [{ rotate: open ? "180deg" : "0deg" }] }}>
                            <ChevronDown size={18} color={p.mutedForeground}/>
                          </Animated.View>
                        </Pressable>
                      </View>

                      {endpoint === "custom" ? (<Input label="Address" placeholder="vault.example.com  ·  192.168.1.10:8080" autoCapitalize="none" autoCorrect={false} keyboardType="url" value={custom} onChangeText={setCustom}/>) : null}

                      {/* live connection status — fixed height, never shifts layout */}
                      <Pressable onPress={() => void runTest(resolvedUrl)} style={{ height: 22, flexDirection: "row", alignItems: "center", gap: 7 }} accessibilityRole="button" accessibilityLabel="Test connection">
                        {test === "testing" ? (<>
                            <ActivityIndicator size="small" color={p.mutedForeground}/>
                            <Text style={{ color: p.mutedForeground, fontSize: 13 }}>
                              Checking connection…
                            </Text>
                          </>) : test === "ok" ? (<>
                            <Dot color={SUCCESS}/>
                            <Text style={{ color: SUCCESS, fontSize: 13, fontWeight: "500" }}>
                              {testMsg}
                            </Text>
                          </>) : test === "fail" ? (<>
                            <Dot color={p.destructive}/>
                            <Text numberOfLines={1} style={{ color: p.destructive, fontSize: 13, flex: 1 }}>
                              {testMsg} · tap to retry
                            </Text>
                          </>) : (<>
                            <Dot color={p.mutedForeground}/>
                            <Text style={{ color: p.mutedForeground, fontSize: 13 }}>
                              Not checked
                            </Text>
                          </>)}
                      </Pressable>
                    </View>)}

                  <View style={{ position: "relative", zIndex: 0 }}>
                    <Button className="w-full" disabled={!canSave} onPress={() => onSave(localMode, localMode === "cloud" ? resolvedUrl : "")} accessibilityLabel="Save connection settings">
                      Save
                    </Button>
                  </View>
                </ScrollView>

                {/* Server dropdown — rendered last so it paints above everything,
            anchored under the selector via measurement. */}
                {open && menu ? (<>
                    <Pressable onPress={() => setOpen(false)} style={{ position: "absolute", top: 0, left: 0, right: 0, bottom: 0 }}/>
                    <Animated.View entering={FadeIn.duration(120)} style={{
                position: "absolute",
                top: menu.top,
                left: menu.left,
                width: menu.width,
                borderRadius: 14,
                borderWidth: 1,
                borderColor: p.border,
                backgroundColor: p.background,
                overflow: "hidden",
                boxShadow: "0px 10px 18px rgba(0,0,0,0.5)",
                elevation: 12,
            }}>
                      <Option label="Entropy Cloud" sub={entropyUrl} active={endpoint === "entropy"} onPress={() => {
                setEndpoint("entropy");
                setOpen(false);
            }} palette={p}/>
                      <Option label="Custom server" sub="DNS / IP / host:port" active={endpoint === "custom"} onPress={() => {
                setEndpoint("custom");
                setOpen(false);
            }} palette={p}/>
                    </Animated.View>
                  </>) : null}
              </Pressable>
            </Animated.View>
          </Pressable>
        </Animated.View>
      </GestureHandlerRootView>
    </Modal>);
}
function Dot({ color }) {
    return <View style={{ width: 8, height: 8, borderRadius: 999, backgroundColor: color }}/>;
}
function ModePill({ label, active, disabled, onPress, palette: p, }) {
    return (<Pressable onPress={() => !disabled && onPress()} disabled={disabled} style={{
            flex: 1,
            paddingVertical: 9,
            borderRadius: 10,
            alignItems: "center",
            backgroundColor: active ? p.primary : "transparent",
            opacity: disabled ? 0.45 : 1,
        }}>
      <Text style={{
            fontSize: 14,
            fontWeight: active ? "700" : "500",
            color: active ? p.primaryForeground : p.foreground,
        }}>
        {label}
      </Text>
    </Pressable>);
}
function Option({ label, sub, active, onPress, palette: p, }) {
    return (<Pressable onPress={onPress} style={{
            flexDirection: "row",
            alignItems: "center",
            paddingHorizontal: 14,
            paddingVertical: 11,
            backgroundColor: active ? p.muted : p.background,
        }}>
      <View style={{ flex: 1 }}>
        <Text style={{ color: p.foreground, fontSize: 14, fontWeight: "500" }}>{label}</Text>
        <Text style={{ color: p.mutedForeground, fontSize: 11, marginTop: 1 }}>{sub}</Text>
      </View>
      {active ? <Check size={16} color={p.primary}/> : null}
    </Pressable>);
}
export default ConnectionSettings;
//# sourceMappingURL=connection-settings.jsx.map