import { createFileRoute, useNavigate } from "@tanstack/react-router";
import { AlertTriangle, Check, Clock, LogIn, ShieldCheck, X } from "lucide-react";
import { useCallback, useEffect, useState } from "react";
import { AuthShell } from "../features/auth/AuthShell";
import { loginProd, startStepUpReauth } from "../features/auth/auth";
import { stashLinkReturn } from "../features/qr/returnTo";
import { consumeStepUpCode, type StepUpStash } from "../features/qr/stepUp";
import { isDesktop, startDesktopLogin } from "../net/desktop";
import {
    qrApprove, qrDeny, qrRequest, StepUpRequiredError,
    type QrPersist, type QrRequestInfo,
} from "../net/qr";
import { useAppStore } from "../store";
import { t } from "../i18n";
import { DeviceTypeIcon, type DeviceKind } from "../ui/glyphs";
import { Button, Callout } from "../ui/primitives";
import s from "./link.module.css";

// 批准页：手机扫码后落地，确认「是哪台设备、从哪来、给什么权限」。要求已登录。
export const Route = createFileRoute("/link")({
    component: LinkApprovePage,
    validateSearch: (search: Record<string, unknown>) =>
    ({
        r: typeof search.r === "string" ? search.r : undefined,
        c: typeof search.c === "string" ? search.c : undefined,
        // p：信任时长选择（persist/once）。step-up 整页跳转回来后据此恢复，避免选择丢失。
        p: typeof search.p === "string" ? search.p : undefined,
    }),
});

type Outcome = "approved" | "denied" | "expired" | "error" | null;

function LinkApprovePage()
{
    const navigate = useNavigate();
    const { r: requestId, c: code, p: persistParam } = Route.useSearch();
    const user = useAppStore((s) => s.user);

    const [ info, setInfo ] = useState<QrRequestInfo | null>(null);
    const [ loadError, setLoadError ] = useState<string | null>(null);
    // 初值优先取 URL 的 p（step-up 跳转回来后恢复选择），否则默认更安全的「仅此次」
    // （受限访客）——避免一路默认到完整会话（full）。
    const [ persist, setPersist ] = useState<QrPersist>(persistParam === "persist" ? "persist" : "once");
    const [ submitting, setSubmitting ] = useState(false);
    const [ outcome, setOutcome ] = useState<Outcome>(null);
    const [ actionError, setActionError ] = useState<string | null>(null);
    // step-up：true=后端要求批准前先做新鲜 prompt=login 再认证（provider 2FA 即此处过）。
    const [ stepUpRequired, setStepUpRequired ] = useState(false);
    // 再认证往返回来后由后端二次拒（403 step_up_required），文案提示并允许重试。
    const [ stepUpRejected, setStepUpRejected ] = useState(false);

    // 未登录：暂存当前 URL 后走标准登录，登录后由首页 beforeLoad 弹回这里。
    const handleSignIn = useCallback(async () =>
    {
        stashLinkReturn(window.location.pathname + window.location.search);
        try
        {
            if (isDesktop())
            {
                await startDesktopLogin();
                navigate({ to: "/" });
            }
            else { await loginProd(); }
        }
        catch (e) { setLoadError(e instanceof Error ? e.message : String(e)); }
    }, [ navigate ]);

    // 已登录且参数齐全：拉取待批准设备信息（含 step_up 标记）。
    useEffect(() =>
    {
        if (!user || !requestId || !code) { return; }
        let cancelled = false;
        qrRequest(requestId, code).then(
            (data) =>
            {
                if (cancelled) { return; }
                setInfo(data);
                setStepUpRequired(data.stepUp);
                if (data.status === "expired") { setOutcome("expired"); }
                else if (data.status === "denied") { setOutcome("denied"); }
                else if (data.status === "approved") { setOutcome("approved"); }
            },
            (e) => { if (!cancelled) { setLoadError(e instanceof Error ? e.message : String(e)); } },
        );
        return () => { cancelled = true; };
    }, [ user, requestId, code ]);

    // doApprove 执行批准；stash 非空时把 step-up 再认证拿到的 code+verifier 一并交给
    // 后端就地核验。403 step_up_required（StepUpRequiredError）单独走「需重新验证」态，
    // 不当成普通错误。
    const doApprove = useCallback(async (stash?: StepUpStash) =>
    {
        if (!requestId || !code) { return; }
        setSubmitting(true);
        setActionError(null);
        setStepUpRejected(false);
        try
        {
            // persist=「信任此设备」→ 完整会话（scope=full）；once=「仅此次」→ 受限访客
            // （scope=guest）。后端按 scope 决定授予的会话级别，二者与 persist 时长一一对应。
            const scope = persist === "persist" ? "full" : "guest";
            await qrApprove(requestId, code, scope, persist, stash?.code, stash?.verifier);
            setOutcome("approved");
        }
        catch (e)
        {
            if (e instanceof StepUpRequiredError) { setStepUpRejected(true); }
            else { setActionError(e instanceof Error ? e.message : String(e)); }
        }
        finally { setSubmitting(false); }
    }, [ requestId, code, persist ]);

    // 再认证往返回来：检测到暂存的 step-up {code, verifier} → 自动调 approve 完成批准
    // → 用完即清（consumeStepUpCode 取出即清）。仅在已登录、设备信息已就绪后跑一次。
    useEffect(() =>
    {
        if (!user || !info || outcome) { return; }
        const stash = consumeStepUpCode();
        if (!stash) { return; }
        void doApprove(stash);
    }, [ user, info, outcome, doApprove ]);

    // handleApprove：批准按钮。step-up 要求且尚无再认证凭证时，先把用户带去做一次
    // 新鲜 prompt=login 再认证（往返回来后由上面的 effect 自动接力 approve）；否则
    // 维持原有直接批准行为不变。
    const handleApprove = async () =>
    {
        if (!requestId || !code) { return; }
        if (stepUpRequired)
        {
            setSubmitting(true);
            setActionError(null);
            setStepUpRejected(false);
            try
            {
                // 把当前「信任时长」选择编进 returnTo：step-up 整页跳转回来后页面重载、
                // React state 复位，必须从 URL 恢复 persist，否则会回落默认、令本应受限
                // 的设备被建成完整会话（#2 根因）。
                const back = new URLSearchParams(window.location.search);
                back.set("p", persist);
                await startStepUpReauth(window.location.pathname + "?" + back.toString());
            }
            catch (e)
            {
                setActionError(e instanceof Error ? e.message : String(e));
                setSubmitting(false);
            }
            // 成功则整页跳转去 provider，本组件随之卸载，不再 setSubmitting。
            return;
        }
        await doApprove();
    };

    const handleDeny = async () =>
    {
        if (!requestId || !code) { return; }
        setSubmitting(true);
        setActionError(null);
        try
        {
            await qrDeny(requestId, code);
            setOutcome("denied");
        }
        catch (e) { setActionError(e instanceof Error ? e.message : String(e)); }
        finally { setSubmitting(false); }
    };

    // ---- 渲染分支 --------------------------------------------------------

    if (!requestId || !code)
    {
        return (
            <AuthShell title={t("qr.approve.title")} hideBrand skipAutospace>
                <Callout tone="error" icon={<AlertTriangle size={16} />}>
                    {t("qr.approve.badLink")}
                </Callout>
                <Button variant="secondary" size="lg" block onClick={() => navigate({ to: "/" })}>
                    {t("qr.approve.backHome")}
                </Button>
            </AuthShell>
        );
    }

    if (!user)
    {
        return (
            <AuthShell
                title={t("qr.approve.title")}
                subtitle={t("qr.approve.signInFirst")}
                hideBrand
                skipAutospace
            >
                <Button
                    variant="primary"
                    size="lg"
                    block
                    leftIcon={<LogIn size={16} />}
                    onClick={() => { void handleSignIn(); }}
                >
                    {t("login.prod.button")}
                </Button>
            </AuthShell>
        );
    }

    if (outcome) { return <OutcomeView outcome={outcome} onHome={() => navigate({ to: "/" })} />; }

    if (loadError)
    {
        return (
            <AuthShell title={t("qr.approve.title")} hideBrand skipAutospace>
                <Callout tone="error" icon={<AlertTriangle size={16} />}>{loadError}</Callout>
                <Button variant="secondary" size="lg" block onClick={() => navigate({ to: "/" })}>
                    {t("qr.approve.backHome")}
                </Button>
            </AuthShell>
        );
    }

    if (!info)
    {
        return (
            <AuthShell title={t("qr.approve.title")} subtitle={t("qr.approve.loading")} hideBrand skipAutospace />
        );
    }

    return (
        <AuthShell title={t("qr.approve.title")} subtitle={t("qr.approve.subtitle")} hideBrand skipAutospace>
            {/* 待批准设备：单行身份块——图标 + 名字 + 来源 IP（monospace 元数据）。 */}
            <div className={s.device}>
                <span className={s.deviceIcon}>
                    <DeviceTypeIcon kind={mapDeviceKind(info.deviceType)} size={24} />
                </span>
                <div className={s.deviceMeta}>
                    <span className={s.deviceName}>{info.deviceName}</span>
                    <span className={s.deviceSub}>
                        {t(`deviceType.${kindKey(info.deviceType)}` as const)}
                        <span className={s.dot}>·</span>
                        <code className={s.ip}>{info.requestIp}</code>
                    </span>
                </div>
            </div>

            {/* 信任时长：两选项分段，选中项得 accent 左色条（同 Callout / Activity 语汇）。 */}
            <div className={s.choices} role="radiogroup" aria-label={t("qr.approve.trustLabel")}>
                <TrustOption
                    value="persist"
                    selected={persist === "persist"}
                    onSelect={setPersist}
                    title={t("qr.approve.trust.title")}
                    hint={t("qr.approve.trust.hint")}
                />
                <TrustOption
                    value="once"
                    selected={persist === "once"}
                    onSelect={setPersist}
                    title={t("qr.approve.once.title")}
                    hint={t("qr.approve.once.hint")}
                />
            </div>

            {/* 权限范围说明：随选中项切换——信任=完整登录、仅此次=受限访客，明确告知
                这台设备将以什么身份登录（非装饰）。 */}
            <Callout tone="info" icon={<ShieldCheck size={16} />}>
                {persist === "persist"
                    ? t("qr.approve.scopeFull")
                    : t("qr.approve.scopeGuest")}
            </Callout>

            {/* step-up：批准前的明确安全步骤——需先验证身份（provider 2FA 即此处过）。 */}
            {stepUpRequired && !stepUpRejected && (
                <Callout tone="info" icon={<ShieldCheck size={16} />}>
                    {t("qr.approve.stepUp.notice")}
                </Callout>
            )}

            {/* 再认证回来仍被后端拒：给方向（凭证过期 / 验证未通过）并允许重试。 */}
            {stepUpRejected && (
                <Callout tone="warn" icon={<AlertTriangle size={16} />}>
                    {t("qr.approve.stepUp.rejected")}
                </Callout>
            )}

            {actionError && (
                <Callout tone="error" icon={<AlertTriangle size={16} />}>{actionError}</Callout>
            )}

            <div className={s.actions}>
                <Button
                    variant="primary"
                    size="lg"
                    block
                    loading={submitting}
                    leftIcon={
                        stepUpRequired ? <ShieldCheck size={16} /> : <Check size={16} />
                    }
                    onClick={() => { void handleApprove(); }}
                >
                    {stepUpRequired
                        ? t("qr.approve.stepUp.button")
                        : t("qr.approve.approve")}
                </Button>
                <Button
                    variant="ghost"
                    size="lg"
                    block
                    disabled={submitting}
                    leftIcon={<X size={16} />}
                    onClick={() => { void handleDeny(); }}
                >
                    {t("qr.approve.deny")}
                </Button>
            </div>
        </AuthShell>
    );
}

function TrustOption(props: {
    value: QrPersist;
    selected: boolean;
    onSelect: (v: QrPersist) => void;
    title: string;
    hint: string;
})
{
    const { value, selected, onSelect, title, hint } = props;
    return (
        <button
            type="button"
            role="radio"
            aria-checked={selected}
            className={`${s.choice} ${selected ? s.choiceOn : ""}`}
            onClick={() => onSelect(value)}
        >
            <span className={s.choiceMark} aria-hidden="true">
                {selected ? <Check size={14} /> : <Clock size={14} />}
            </span>
            <span className={s.choiceText}>
                <span className={s.choiceTitle}>{title}</span>
                <span className={s.choiceHint} data-jz-level="paragraph">{hint}</span>
            </span>
        </button>
    );
}

function OutcomeView(props: { outcome: Exclude<Outcome, null>; onHome: () => void })
{
    const { outcome, onHome } = props;
    const map = {
        approved: { tone: "ok" as const, icon: <ShieldCheck size={16} />,
                    title: t("qr.approve.doneApprovedTitle"), body: t("qr.approve.doneApproved") },
        denied:   { tone: "warn" as const, icon: <X size={16} />,
                    title: t("qr.approve.doneDeniedTitle"), body: t("qr.approve.doneDenied") },
        expired:  { tone: "warn" as const, icon: <Clock size={16} />,
                    title: t("qr.approve.expiredTitle"), body: t("qr.approve.expired") },
        error:    { tone: "error" as const, icon: <AlertTriangle size={16} />,
                    title: t("qr.approve.errorTitle"), body: t("qr.approve.error") },
    }[outcome];
    return (
        <AuthShell title={map.title} hideBrand skipAutospace>
            <Callout tone={map.tone} icon={map.icon}>{map.body}</Callout>
            <Button variant="secondary" size="lg" block onClick={onHome}>
                {t("qr.approve.backHome")}
            </Button>
        </AuthShell>
    );
}

// mapDeviceKind：契约 device_type → DeviceTypeIcon 的 DeviceKind（与 DeviceStrip
// 同口径；批准页独立一份，不改动既有组件）。
function mapDeviceKind(type: string): DeviceKind
{
    const v = type.toLowerCase();
    if (v === "shortcut") { return "shortcut"; }
    if (v.includes("mac") || v === "darwin") { return "macos"; }
    if (v.includes("win")) { return "windows"; }
    if (v.includes("linux")) { return "linux"; }
    if (v.includes("ios") || v.includes("iphone") || v.includes("ipad")) { return "ios"; }
    if (v.includes("android")) { return "android"; }
    return "unknown";
}

// kindKey：device_type → deviceType.* i18n key 的已知分支，未知回退 browser。
function kindKey(type: string): "browser" | "macos" | "windows" | "linux" | "ios" | "shortcut"
{
    const v = type.toLowerCase();
    if (v === "shortcut") { return "shortcut"; }
    if (v.includes("mac") || v === "darwin") { return "macos"; }
    if (v.includes("win")) { return "windows"; }
    if (v.includes("linux")) { return "linux"; }
    if (v.includes("ios") || v.includes("iphone") || v.includes("ipad")) { return "ios"; }
    return "browser";
}
