import { createFileRoute, useNavigate } from "@tanstack/react-router";
import { AlertTriangle, ArrowLeft, ArrowRight, RefreshCw, ScanLine } from "lucide-react";
import { useCallback, useEffect, useRef, useState } from "react";
import { AuthShell } from "../features/auth/AuthShell";
import { syncWebDeviceName } from "../features/auth/auth";
import { QrCanvas } from "../features/qr/QrCanvas";
import { persistDesktopDeviceName } from "../net/desktop";
import { pollQrStatus, qrStart, type QrStartResp, type QrStatus } from "../net/qr";
import { readInjectedDeviceType } from "../store/helpers";
import { useAppStore } from "../store";
import { t } from "../i18n";
import { isAsciiDeviceName } from "../utils/format";
import { StateDot } from "../ui/glyphs";
import { Button, Callout, TextField } from "../ui/primitives";
import s from "./link_.new.module.css";

// 显码页：有人借了一台陌生设备，扫码把它接入自己的 cdrop。它本身公开（start /
// status 无需登录），故不设路由守卫——已登录用户也可经此把另一设备接入。
export const Route = createFileRoute("/link_/new")({
    component: LinkNewPage,
});

type Step = "name" | "show";

function LinkNewPage()
{
    const navigate = useNavigate();
    const setAuth = useAppStore((s) => s.setAuth);
    const setSelfDeviceName = useAppStore((s) => s.setSelfDeviceName);

    const [ step, setStep ] = useState<Step>("name");
    const [ name, setName ] = useState(suggestDeviceName);
    const [ session, setSession ] = useState<QrStartResp | null>(null);
    const [ phase, setPhase ] = useState<QrStatus["status"]>("pending");
    const [ error, setError ] = useState<string | null>(null);
    const [ starting, setStarting ] = useState(false);

    // 轮询的取消句柄。换二维码 / 卸载时调用即停。
    const cancelPollRef = useRef<(() => void) | null>(null);

    const onApproved = useCallback((st: QrStatus) =>
    {
        if (st.status !== "approved" || !st.accessToken || !st.user) { return; }
        setAuth({
            accessToken: st.accessToken,
            user: { id: st.user.id, name: st.user.name, avatar: st.user.avatar },
        });
        // 设备名以批准方下发的为权威（服务端登记的名字），回退到本地输入。
        const finalName = st.deviceName?.trim() || name.trim();
        setSelfDeviceName(finalName);
        persistDesktopDeviceName(finalName);
        syncWebDeviceName(finalName);
        navigate({ to: "/" });
    }, [ name, navigate, setAuth, setSelfDeviceName ]);

    const begin = useCallback(async (deviceName: string) =>
    {
        setError(null);
        setStarting(true);
        try
        {
            const resp = await qrStart({
                deviceName,
                deviceType: readInjectedDeviceType(),
            });
            setSession(resp);
            setPhase("pending");
            setStep("show");
        }
        catch (e)
        {
            setError(e instanceof Error ? e.message : String(e));
        }
        finally { setStarting(false); }
    }, []);

    // 拿到 session 即起长轮询；session 变化（重新生成）时换新轮询。
    useEffect(() =>
    {
        if (!session) { return; }
        cancelPollRef.current?.();
        const cancel = pollQrStatus(session.requestId, session.pollSecret, {
            onResolved: (st) =>
            {
                setPhase(st.status);
                if (st.status === "approved") { onApproved(st); }
            },
            onError: () => { /* 单轮抖动：轮询循环自重试，UI 保持等待态 */ },
        });
        cancelPollRef.current = cancel;
        return () => { cancel(); cancelPollRef.current = null; };
    }, [ session, onApproved ]);

    const handleContinue = () =>
    {
        const trimmed = name.trim();
        if (!trimmed) { return; }
        if (!isAsciiDeviceName(trimmed))
        {
            setError(t("settings.deviceName.asciiOnly"));
            return;
        }
        void begin(trimmed);
    };

    const handleRegenerate = () =>
    {
        setError(null);
        void begin(name.trim());
    };

    // 回上一步：弃掉当前二维码会话，退回命名步骤（轮询随 session 清空由 effect 清理）。
    const handleBackToName = () =>
    {
        cancelPollRef.current?.();
        cancelPollRef.current = null;
        setSession(null);
        setError(null);
        setStep("name");
    };

    if (step === "name")
    {
        return (
            <AuthShell
                title={t("qr.show.title")}
                subtitle={t("qr.show.subtitle")}
                hideBrand
                skipAutospace
            >
                {error && (
                    <Callout tone="error" icon={<AlertTriangle size={16} />}>{error}</Callout>
                )}
                <TextField
                    label={t("setup.field")}
                    hint={t("qr.show.nameHint")}
                    value={name}
                    onChange={(e) => setName(e.currentTarget.value)}
                    onKeyDown={(e) =>
                    {
                        if (e.key === "Enter" && name.trim())
                        {
                            e.preventDefault();
                            handleContinue();
                        }
                    }}
                    autoFocus
                />
                <Button
                    variant="primary"
                    size="lg"
                    block
                    loading={starting}
                    rightIcon={<ArrowRight size={16} />}
                    onClick={handleContinue}
                    disabled={!name.trim()}
                >
                    {t("qr.show.generate")}
                </Button>
                <Button
                    variant="ghost"
                    size="lg"
                    block
                    leftIcon={<ArrowLeft size={16} />}
                    onClick={() => navigate({ to: "/" })}
                >
                    {t("qr.show.back")}
                </Button>
            </AuthShell>
        );
    }

    return (
        <AuthShell title={t("qr.show.scanTitle")} hideBrand skipAutospace>
            {error && (
                <Callout tone="error" icon={<AlertTriangle size={16} />}>{error}</Callout>
            )}

            <div className={s.stage}>
                <div className={s.plate}>
                    {session && <QrCanvas value={session.qrPayload} />}
                </div>

                <StatusLine phase={phase} />
            </div>

            <ol className={s.steps} data-jz-level="paragraph">
                <li>{t("qr.show.howto1")}</li>
                <li>{t("qr.show.howto2")}</li>
            </ol>

            {(phase === "expired" || phase === "denied") && (
                <Callout
                    tone={phase === "denied" ? "error" : "warn"}
                    icon={<AlertTriangle size={16} />}
                >
                    {phase === "denied" ? t("qr.show.denied") : t("qr.show.expired")}
                </Callout>
            )}

            {(phase === "expired" || phase === "denied") && (
                <Button
                    variant="secondary"
                    size="lg"
                    block
                    leftIcon={<RefreshCw size={16} />}
                    onClick={handleRegenerate}
                >
                    {t("qr.show.regenerate")}
                </Button>
            )}

            {/* 始终给一个明确退出口：回到命名步骤，避免卡在显码 / 终态页。 */}
            {phase !== "approved" && (
                <Button
                    variant="ghost"
                    size="lg"
                    block
                    leftIcon={<ArrowLeft size={16} />}
                    onClick={handleBackToName}
                >
                    {t("qr.show.backToName")}
                </Button>
            )}
        </AuthShell>
    );
}

// 显码页的等待态：一行平静的状态，pending 时 accent 脉冲点 + 「等待批准」。
function StatusLine(props: { phase: QrStatus["status"] })
{
    const { phase } = props;
    if (phase === "approved")
    {
        return (
            <div className={s.statusLine}>
                <StateDot tone="online" size={8} />
                <span>{t("qr.show.approved")}</span>
            </div>
        );
    }
    if (phase === "expired" || phase === "denied") { return null; }
    return (
        <div className={s.statusLine}>
            <span className={s.pulse} aria-hidden="true" />
            <span className={s.waitText}>
                <ScanLine size={14} />
                {t("qr.show.waiting")}
            </span>
        </div>
    );
}

// suggestDeviceName：UA 预填一个可读的默认设备名（与 /setup 同口径），可编辑。
function suggestDeviceName(): string
{
    const ua = navigator.userAgent;
    let browser = "Browser";
    if (ua.includes("Firefox/")) { browser = "Firefox"; }
    else if (ua.includes("Edg/")) { browser = "Edge"; }
    else if (ua.includes("Chrome/")) { browser = "Chrome"; }
    else if (ua.includes("Safari/")) { browser = "Safari"; }

    let os = "Desktop";
    if (ua.includes("Mac")) { os = "macOS"; }
    else if (ua.includes("Windows")) { os = "Windows"; }
    else if (ua.includes("Linux")) { os = "Linux"; }

    return `${browser}-${os}-${Math.floor(Math.random() * 0xffffff).toString(16).padStart(6, "0")}`;
}
