"use client";

import "@xterm/xterm/css/xterm.css";
import { useEffect, useRef, useState } from "react";
import { useForm } from "react-hook-form";
import * as z from "zod";
import { Button } from "@app/components/ui/button";
import { Input } from "@app/components/ui/input";
import { Textarea } from "@app/components/ui/textarea";
import {
    Form,
    FormControl,
    FormField,
    FormItem,
    FormLabel,
    FormMessage
} from "@app/components/ui/form";
import { GetBrowserTargetResponse } from "@server/routers/browserGatewayTarget";
import {
    Card,
    CardContent,
    CardHeader,
    CardTitle,
    CardDescription
} from "@app/components/ui/card";
import Link from "next/link";
import { ExternalLink, Loader2 } from "lucide-react";
import { Alert, AlertDescription } from "@app/components/ui/alert";
import { HorizontalTabs } from "@app/components/HorizontalTabs";
import type { SignSshKeyResponse } from "@server/routers/ssh/types";
import { useTranslations } from "next-intl";
import BrandedAuthSurface from "@app/components/BrandedAuthSurface";
import PoweredByPangolin from "@app/components/PoweredByPangolin";
import AuthPageFooterNotices from "@app/components/AuthPageFooterNotices";
import {
    loadEncryptedLocalStorage,
    saveEncryptedLocalStorage
} from "@app/lib/secureLocalStorage";

type AuthTab = "password" | "privateKey";

type SshCredentialsForm = {
    username: string;
    password: string;
    privateKey: string;
};

type ConnectCredentials = {
    username: string;
    password?: string;
    privateKey?: string;
    certificate?: string;
};

const DEFAULT_SSH_CREDENTIALS: SshCredentialsForm = {
    username: "",
    password: "",
    privateKey: ""
};

export default function SshClient({
    target,
    error,
    signedKeyData,
    privateKey: signedPrivateKey,
    primaryColor
}: {
    target: GetBrowserTargetResponse | null;
    error: string | null;
    signedKeyData?: SignSshKeyResponse | null;
    privateKey?: string | null;
    primaryColor?: string | null;
}) {
    const STORAGE_KEY = "pangolin_ssh_credentials";
    const t = useTranslations();
    const resourceName = target?.name?.trim() || null;

    const passwordTabSchema = z.object({
        username: z.string().min(1, { message: t("usernameRequired") }),
        password: z.string().min(1, { message: t("passwordRequired") })
    });

    const privateKeyTabSchema = z.object({
        username: z.string().min(1, { message: t("usernameRequired") }),
        privateKey: z.string().min(1, { message: t("sshPrivateKeyRequired") })
    });

    const form = useForm<SshCredentialsForm>({
        defaultValues: DEFAULT_SSH_CREDENTIALS
    });

    useEffect(() => {
        let cancelled = false;

        void loadEncryptedLocalStorage<SshCredentialsForm>(
            STORAGE_KEY,
            target?.authToken
        ).then((saved) => {
            if (cancelled || !saved) return;
            form.reset({ ...DEFAULT_SSH_CREDENTIALS, ...saved });
        });

        return () => {
            cancelled = true;
        };
    }, [form, target?.authToken]);

    function handleKeyFile(e: React.ChangeEvent<HTMLInputElement>) {
        const file = e.target.files?.[0];
        if (!file) return;
        const reader = new FileReader();
        reader.onload = (ev) => {
            const text = ev.target?.result;
            if (typeof text === "string") {
                form.setValue("privateKey", text, { shouldDirty: true });
            }
        };
        reader.readAsText(file);
        e.target.value = "";
    }

    const [connected, setConnected] = useState(false);
    const [connecting, setConnecting] = useState(false);
    const [connectError, setConnectError] = useState<string | null>(null);
    const [sessionClosedCode, setSessionClosedCode] = useState<number | null>(
        null
    );

    const terminalRef = useRef<HTMLDivElement>(null);
    const xtermRef = useRef<import("@xterm/xterm").Terminal | null>(null);
    const fitAddonRef = useRef<import("@xterm/addon-fit").FitAddon | null>(
        null
    );
    const wsRef = useRef<WebSocket | null>(null);

    // Mount the terminal div once connected.
    useEffect(() => {
        if (!connected || !terminalRef.current) return;

        let cancelled = false;

        (async () => {
            const [{ Terminal }, { FitAddon }, { WebLinksAddon }] =
                await Promise.all([
                    import("@xterm/xterm"),
                    import("@xterm/addon-fit"),
                    import("@xterm/addon-web-links")
                ]);
            if (cancelled || !terminalRef.current) return;

            const terminal = new Terminal({
                cursorBlink: true,
                fontSize: 14,
                fontFamily: "Menlo, Monaco, 'Courier New', monospace",
                theme: {
                    background: "#0d0d0d",
                    foreground: "#f0f0f0"
                },
                scrollback: 5000
            });

            const fitAddon = new FitAddon();
            const webLinksAddon = new WebLinksAddon();
            terminal.loadAddon(fitAddon);
            terminal.loadAddon(webLinksAddon);

            terminal.open(terminalRef.current);
            fitAddon.fit();

            xtermRef.current = terminal;
            fitAddonRef.current = fitAddon;

            terminal.onData((data) => {
                if (wsRef.current?.readyState === WebSocket.OPEN) {
                    wsRef.current.send(JSON.stringify({ type: "data", data }));
                }
            });

            terminal.onResize(({ cols, rows }) => {
                if (wsRef.current?.readyState === WebSocket.OPEN) {
                    wsRef.current.send(
                        JSON.stringify({ type: "resize", cols, rows })
                    );
                }
            });

            const { cols, rows } = terminal;
            if (wsRef.current?.readyState === WebSocket.OPEN) {
                wsRef.current.send(
                    JSON.stringify({ type: "resize", cols, rows })
                );
            }
        })().catch(console.error);

        return () => {
            cancelled = true;
        };
    }, [connected]);

    useEffect(() => {
        const onResize = () => fitAddonRef.current?.fit();
        window.addEventListener("resize", onResize);
        return () => window.removeEventListener("resize", onResize);
    }, []);

    useEffect(() => {
        return () => {
            wsRef.current?.close();
            xtermRef.current?.dispose();
        };
    }, []);

    useEffect(() => {
        if (signedKeyData && signedPrivateKey && target) {
            connect({
                username: signedKeyData.sshUsername,
                privateKey: signedPrivateKey,
                certificate: signedKeyData.certificate
            });
        }
    }, []);

    function connect(
        override?: ConnectCredentials,
        authMethod: AuthTab = "password"
    ) {
        setConnecting(true);
        setSessionClosedCode(null);
        setConnectError(null);

        if (!target) {
            setConnectError(t("sshErrorNoTarget"));
            setConnecting(false);
            return;
        }

        const values = form.getValues();
        const username = override?.username ?? values.username;
        const password =
            override?.password ??
            (authMethod === "password" ? values.password : "");
        const privateKey =
            override?.privateKey ??
            (authMethod === "privateKey" ? values.privateKey : "");
        const certificate = override?.certificate;

        const proxyAddress = `${window.location.protocol === "https:" ? "wss" : "ws"}://${window.location.host}/gateway/ssh`;
        const url = new URL(proxyAddress);
        url.searchParams.set(
            "mode",
            target.authDaemonMode === "native" ? "native" : "proxy"
        );
        if (target.authDaemonMode !== "native") {
            url.searchParams.set("host", target.ip ?? "");
            url.searchParams.set("port", String(target.port ?? 22));
        }
        url.searchParams.set("username", username);
        url.searchParams.set("authToken", target.authToken ?? "");

        const ws = new WebSocket(url.toString(), ["ssh"]);
        wsRef.current = ws;

        let authConfirmed = false;
        let authErrorShown = false;
        let socketOpened = false;

        ws.onopen = () => {
            socketOpened = true;
            ws.send(
                JSON.stringify({
                    type: "auth",
                    password,
                    privateKey,
                    certificate
                })
            );
            if (!override) {
                void saveEncryptedLocalStorage(
                    STORAGE_KEY,
                    form.getValues(),
                    target.authToken
                );
            }
        };

        ws.onmessage = (evt) => {
            if (typeof evt.data === "string") {
                try {
                    const msg = JSON.parse(evt.data as string) as {
                        type: string;
                        data?: string;
                        error?: string;
                    };
                    if (msg.type === "data" && msg.data) {
                        if (!authConfirmed) {
                            authConfirmed = true;
                            setConnecting(false);
                            setConnected(true);
                        }
                        xtermRef.current?.write(msg.data);
                    } else if (msg.type === "error") {
                        if (!authConfirmed) {
                            authErrorShown = true;
                            setConnecting(false);
                            setConnectError(
                                msg.error ?? t("sshErrorAuthFailed")
                            );
                        } else {
                            xtermRef.current?.writeln(
                                `\r\n\x1b[31m${t("sshTerminalError", { error: msg.error ?? "" })}\x1b[0m\r\n`
                            );
                        }
                    }
                } catch {
                    if (!authConfirmed) {
                        authConfirmed = true;
                        setConnecting(false);
                        setConnected(true);
                    }
                    xtermRef.current?.write(evt.data);
                }
            } else if (evt.data instanceof Blob) {
                evt.data.text().then((text) => {
                    if (!authConfirmed) {
                        authConfirmed = true;
                        setConnecting(false);
                        setConnected(true);
                    }
                    xtermRef.current?.write(text);
                });
            }
        };

        ws.onerror = () => {
            setConnecting(false);
            setConnected(false);
            setConnectError(t("sshErrorWebSocket"));
        };

        ws.onclose = (evt) => {
            wsRef.current = null;
            setConnecting(false);
            const isCleanClose = evt.wasClean || evt.code === 1000;
            if (isCleanClose && (authConfirmed || socketOpened)) {
                xtermRef.current?.dispose();
                xtermRef.current = null;
                setConnected(false);
                setSessionClosedCode(evt.code);
                return;
            }
            if (authConfirmed) {
                setConnected(false);
                xtermRef.current?.writeln(
                    `\r\n\x1b[33m${t("sshConnectionClosedCode", { code: evt.code })}\x1b[0m\r\n`
                );
            }
            if (!authConfirmed && !authErrorShown) {
                setConnectError(t("sshErrorConnectionClosed"));
            }
        };
    }

    function disconnect() {
        wsRef.current?.close();
        xtermRef.current?.dispose();
        xtermRef.current = null;
        setConnected(false);
    }

    function applyTabSchemaErrors(
        schema: z.ZodObject<z.ZodRawShape>,
        values: SshCredentialsForm
    ) {
        form.clearErrors();
        const result = schema.safeParse(values);
        if (result.success) return true;
        for (const issue of result.error.issues) {
            const field = issue.path[0];
            if (typeof field === "string") {
                form.setError(field as keyof SshCredentialsForm, {
                    message: issue.message
                });
            }
        }
        return false;
    }

    function onPasswordSubmit(e: React.FormEvent) {
        e.preventDefault();
        setConnectError(null);
        const values = form.getValues();
        if (!applyTabSchemaErrors(passwordTabSchema, values)) return;
        connect(undefined, "password");
    }

    function onPrivateKeySubmit(e: React.FormEvent) {
        e.preventDefault();
        setConnectError(null);
        const values = form.getValues();
        if (!applyTabSchemaErrors(privateKeyTabSchema, values)) return;
        connect(undefined, "privateKey");
    }

    if (signedKeyData && signedPrivateKey) {
        return (
            <>
                {!connected && (
                    <div className="flex items-center justify-center">
                        <Card className="w-full max-w-md">
                            <CardHeader>
                                <CardTitle>{t("sshTitle")}</CardTitle>
                                <CardDescription>
                                    {t("sshConnectingDescription")}
                                </CardDescription>
                            </CardHeader>
                            <CardContent className="flex flex-col items-center space-y-4">
                                {!connectError && (
                                    <div className="flex items-center space-x-2">
                                        <Loader2 className="h-5 w-5 animate-spin" />
                                        <span>
                                            {connecting
                                                ? t("sshConnecting")
                                                : t("sshInitializing")}
                                        </span>
                                    </div>
                                )}
                                {connectError && (
                                    <Alert
                                        variant="destructive"
                                        className="w-full"
                                    >
                                        <AlertDescription>
                                            {connectError}
                                        </AlertDescription>
                                    </Alert>
                                )}
                            </CardContent>
                        </Card>
                    </div>
                )}
                {connected && (
                    <div className="fixed inset-0 z-50 flex flex-col bg-neutral-900">
                        <div
                            ref={terminalRef}
                            className="flex-1 overflow-hidden"
                            style={{ minHeight: 0 }}
                        />
                    </div>
                )}
            </>
        );
    }

    if (error) {
        return (
            <BrandedAuthSurface primaryColor={primaryColor}>
                <PoweredByPangolin />
                <Card className="w-full">
                    <CardHeader>
                        <CardTitle>{t("sshTitle")}</CardTitle>
                    </CardHeader>
                    <CardContent>
                        <Alert variant="destructive">
                            <AlertDescription>{error}</AlertDescription>
                        </Alert>
                    </CardContent>
                </Card>
            </BrandedAuthSurface>
        );
    }

    if (sessionClosedCode !== null) {
        return (
            <BrandedAuthSurface primaryColor={primaryColor}>
                <PoweredByPangolin />
                <Card className="w-full max-w-md">
                    <CardHeader>
                        <CardTitle>{t("sshTitle")}</CardTitle>
                        <CardDescription>
                            {t("sshConnectionClosedCode", {
                                code: sessionClosedCode
                            })}
                        </CardDescription>
                    </CardHeader>
                    <CardContent className="space-y-4">
                        <Alert>
                            <AlertDescription>
                                This session has ended. You can close this tab
                                now.
                            </AlertDescription>
                        </Alert>
                        <Button
                            type="button"
                            className="w-full"
                            onClick={() => window.close()}
                        >
                            {t("close")}
                        </Button>
                    </CardContent>
                </Card>
                <AuthPageFooterNotices />
            </BrandedAuthSurface>
        );
    }

    return (
        <>
            {!connected && (
                <BrandedAuthSurface primaryColor={primaryColor}>
                    <PoweredByPangolin />
                    <Card className="w-full">
                        <CardHeader>
                            <CardTitle>{t("sshSignInTitle")}</CardTitle>
                            <CardDescription>
                                {resourceName
                                    ? `${t("sshSignInDescription")} (${resourceName})`
                                    : t("sshSignInDescription")}
                            </CardDescription>
                        </CardHeader>
                        <CardContent>
                            <Form {...form}>
                                <HorizontalTabs
                                    clientSide
                                    defaultTab={0}
                                    items={[
                                        {
                                            title: t("sshPasswordTab"),
                                            href: "#"
                                        },
                                        {
                                            title: t("sshPrivateKeyTab"),
                                            href: "#"
                                        }
                                    ]}
                                >
                                    <form
                                        onSubmit={onPasswordSubmit}
                                        className="space-y-4 mt-4 p-1"
                                    >
                                        <FormField
                                            control={form.control}
                                            name="username"
                                            render={({ field }) => (
                                                <FormItem>
                                                    <FormLabel>
                                                        {t("username")}
                                                    </FormLabel>
                                                    <FormControl>
                                                        <Input {...field} />
                                                    </FormControl>
                                                    <FormMessage />
                                                </FormItem>
                                            )}
                                        />
                                        <FormField
                                            control={form.control}
                                            name="password"
                                            render={({ field }) => (
                                                <FormItem>
                                                    <FormLabel>
                                                        {t("password")}
                                                    </FormLabel>
                                                    <FormControl>
                                                        <Input
                                                            type="password"
                                                            {...field}
                                                        />
                                                    </FormControl>
                                                    <FormMessage />
                                                </FormItem>
                                            )}
                                        />
                                        <div className="mt-4 space-y-3">
                                            <Button
                                                type="submit"
                                                loading={connecting}
                                                disabled={connecting}
                                                className="w-full"
                                            >
                                                {t("sshAuthenticate")}
                                            </Button>
                                            {connectError && (
                                                <Alert variant="destructive">
                                                    <AlertDescription>
                                                        {connectError}
                                                    </AlertDescription>
                                                </Alert>
                                            )}
                                        </div>
                                    </form>

                                    <form
                                        onSubmit={onPrivateKeySubmit}
                                        className="space-y-4 mt-4 p-1"
                                    >
                                        <p className="text-sm text-muted-foreground">
                                            {t("sshPrivateKeyDisclaimer")}{" "}
                                            <Link
                                                href="https://docs.pangolin.net/manage/ssh#authentication-method"
                                                target="_blank"
                                                rel="noopener noreferrer"
                                                className="text-primary hover:underline inline-flex items-center gap-1"
                                            >
                                                {t("sshLearnMore")}
                                                <ExternalLink className="size-3.5 shrink-0" />
                                            </Link>
                                        </p>
                                        <FormField
                                            control={form.control}
                                            name="username"
                                            render={({ field }) => (
                                                <FormItem>
                                                    <FormLabel>
                                                        {t("username")}
                                                    </FormLabel>
                                                    <FormControl>
                                                        <Input {...field} />
                                                    </FormControl>
                                                    <FormMessage />
                                                </FormItem>
                                            )}
                                        />
                                        <FormField
                                            control={form.control}
                                            name="privateKey"
                                            render={({ field }) => (
                                                <FormItem>
                                                    <FormLabel>
                                                        {t(
                                                            "sshPrivateKeyField"
                                                        )}
                                                    </FormLabel>
                                                    <FormControl>
                                                        <Textarea
                                                            {...field}
                                                            placeholder={t(
                                                                "sshPrivateKeyPlaceholder"
                                                            )}
                                                            rows={5}
                                                            className="font-mono text-xs"
                                                        />
                                                    </FormControl>
                                                    <FormMessage />
                                                </FormItem>
                                            )}
                                        />
                                        <FormItem>
                                            <FormLabel>
                                                {t("sshPrivateKeyFile")}
                                            </FormLabel>
                                            <FormControl>
                                                <Input
                                                    type="file"
                                                    accept=".pem,.key,.pub,*"
                                                    onChange={handleKeyFile}
                                                />
                                            </FormControl>
                                        </FormItem>
                                        <div className="mt-4 space-y-3">
                                            <Button
                                                type="submit"
                                                loading={connecting}
                                                disabled={connecting}
                                                className="w-full"
                                            >
                                                {t("sshAuthenticate")}
                                            </Button>
                                            {connectError && (
                                                <Alert variant="destructive">
                                                    <AlertDescription>
                                                        {connectError}
                                                    </AlertDescription>
                                                </Alert>
                                            )}
                                        </div>
                                    </form>
                                </HorizontalTabs>
                            </Form>
                        </CardContent>
                    </Card>
                    <AuthPageFooterNotices />
                </BrandedAuthSurface>
            )}

            {connected && (
                <div className="fixed inset-0 z-50 flex flex-col bg-neutral-900">
                    {/* <div className="flex flex-wrap items-center gap-2 bg-black p-2 text-white">
                        <Button
                            size="sm"
                            variant="destructive"
                            onClick={disconnect}
                        >
                            {t("sshTerminate")}
                        </Button>
                    </div> */}
                    <div
                        ref={terminalRef}
                        className="flex-1 overflow-hidden"
                        style={{ minHeight: 0 }}
                    />
                </div>
            )}
        </>
    );
}
