"use client";

import CopyToClipboard from "@app/components/CopyToClipboard";
import {
    InfoSection,
    InfoSectionContent,
    InfoSections,
    InfoSectionTitle
} from "@app/components/InfoSection";
import {
    SettingsContainer,
    SettingsSection,
    SettingsSectionBody,
    SettingsSectionDescription,
    SettingsSectionHeader,
    SettingsSectionTitle
} from "@app/components/Settings";
import HeaderTitle from "@app/components/SettingsSectionTitle";
import { Button } from "@app/components/ui/button";
import {
    Form,
    FormControl,
    FormDescription,
    FormField,
    FormItem,
    FormLabel,
    FormMessage
} from "@app/components/ui/form";
import { Input } from "@app/components/ui/input";
import { useEnvContext } from "@app/hooks/useEnvContext";
import { toast } from "@app/hooks/useToast";
import { createApiClient, formatAxiosError } from "@app/lib/api";
import { zodResolver } from "@hookform/resolvers/zod";
import {
    CreateClientBody,
    CreateClientResponse,
    PickClientDefaultsResponse
} from "@server/routers/client";
import { AxiosResponse } from "axios";
import { ChevronDown, ChevronUp } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";

import { OlmInstallCommands } from "@app/components/olm-install-commands";
import { useTranslations } from "next-intl";

type ClientType = "olm";

interface TunnelTypeOption {
    id: ClientType;
    title: string;
    description: string;
    disabled?: boolean;
}

export default function Page() {
    const { env } = useEnvContext();
    const api = createApiClient({ env });
    const { orgId } = useParams();
    const router = useRouter();
    const t = useTranslations();

    const createClientFormSchema = z.object({
        name: z
            .string()
            .min(2, { message: t("nameMin", { len: 2 }) })
            .max(30, { message: t("nameMax", { len: 30 }) }),
        method: z.enum(["olm"]),
        subnet: z.union([z.ipv4(), z.ipv6()]).refine((val) => val.length > 0, {
            message: t("subnetRequired")
        })
    });

    type CreateClientFormValues = z.infer<typeof createClientFormSchema>;

    const [tunnelTypes, setTunnelTypes] = useState<
        ReadonlyArray<TunnelTypeOption>
    >([
        {
            id: "olm",
            title: t("olmTunnel"),
            description: t("olmTunnelDescription"),
            disabled: true
        }
    ]);

    const [loadingPage, setLoadingPage] = useState(true);

    const [olmId, setOlmId] = useState("");
    const [olmSecret, setOlmSecret] = useState("");
    const [olmVersion, setOlmVersion] = useState("latest");

    const [createLoading, setCreateLoading] = useState(false);
    const [showAdvancedSettings, setShowAdvancedSettings] = useState(false);

    const [clientDefaults, setClientDefaults] =
        useState<PickClientDefaultsResponse | null>(null);

    const form = useForm<CreateClientFormValues>({
        resolver: zodResolver(createClientFormSchema),
        defaultValues: {
            name: "",
            method: "olm",
            subnet: ""
        }
    });

    async function onSubmit(data: CreateClientFormValues) {
        setCreateLoading(true);

        if (!clientDefaults) {
            toast({
                variant: "destructive",
                title: t("errorCreatingClient"),
                description: t("clientDefaultsNotFound")
            });
            setCreateLoading(false);
            return;
        }

        const payload: CreateClientBody = {
            name: data.name,
            type: data.method as "olm",
            olmId: clientDefaults.olmId,
            secret: clientDefaults.olmSecret,
            subnet: data.subnet
        };

        const res = await api
            .put<
                AxiosResponse<CreateClientResponse>
            >(`/org/${orgId}/client`, payload)
            .catch((e) => {
                toast({
                    variant: "destructive",
                    title: t("errorCreatingClient"),
                    description: formatAxiosError(e)
                });
            });

        if (res && res.status === 201) {
            const data = res.data.data;
            router.push(`/${orgId}/settings/clients/machine/${data.niceId}`);
        }

        setCreateLoading(false);
    }

    useEffect(() => {
        const load = async () => {
            setLoadingPage(true);

            try {
                const controller = new AbortController();
                const timeoutId = setTimeout(() => controller.abort(), 3000);

                const response = await fetch(
                    `https://api.github.com/repos/fosrl/olm/releases/latest`,
                    { signal: controller.signal }
                );

                clearTimeout(timeoutId);

                if (!response.ok) {
                    throw new Error(
                        t("olmErrorFetchReleases", {
                            err: response.statusText
                        })
                    );
                }
                const data = await response.json();
                const latestVersion = data.tag_name;
                setOlmVersion(latestVersion);
            } catch (error) {
                if (error instanceof Error && error.name === "AbortError") {
                    console.error(t("olmErrorFetchTimeout"));
                } else {
                    console.error(
                        t("olmErrorFetchLatest", {
                            err:
                                error instanceof Error
                                    ? error.message
                                    : String(error)
                        })
                    );
                }
            }

            await api
                .get(`/org/${orgId}/pick-client-defaults`)
                .catch((e) => {
                    form.setValue("method", "olm");
                })
                .then((res) => {
                    if (res && res.status === 200) {
                        const data = res.data.data;

                        setClientDefaults(data);

                        const olmId = data.olmId;
                        const olmSecret = data.olmSecret;

                        setOlmId(olmId);
                        setOlmSecret(olmSecret);

                        if (data.subnet) {
                            form.setValue("subnet", data.subnet);
                        }

                        setTunnelTypes((prev: any) => {
                            return prev.map((item: any) => {
                                return { ...item, disabled: false };
                            });
                        });
                    }
                });

            setLoadingPage(false);
        };

        load();
    }, []);

    return (
        <>
            <div className="flex justify-between">
                <HeaderTitle
                    title={t("createClient")}
                    description={t("createClientDescription")}
                />
                <Button
                    variant="outline"
                    onClick={() => {
                        router.push(`/${orgId}/settings/clients`);
                    }}
                >
                    {t("seeAllClients")}
                </Button>
            </div>

            {!loadingPage && (
                <div>
                    <SettingsContainer>
                        <SettingsSection>
                            <SettingsSectionHeader>
                                <SettingsSectionTitle>
                                    {t("clientInformation")}
                                </SettingsSectionTitle>
                            </SettingsSectionHeader>
                            <SettingsSectionBody>
                                <Form {...form}>
                                    <form
                                        onKeyDown={(e) => {
                                            if (e.key === "Enter") {
                                                e.preventDefault(); // block default enter refresh
                                            }
                                        }}
                                        className="space-y-4 grid gap-4 grid-cols-1 md:grid-cols-2 items-start"
                                        id="create-client-form"
                                    >
                                        <FormField
                                            control={form.control}
                                            name="name"
                                            render={({ field }) => (
                                                <FormItem>
                                                    <FormLabel>
                                                        {t("name")}
                                                    </FormLabel>
                                                    <FormControl>
                                                        <Input
                                                            autoComplete="off"
                                                            {...field}
                                                        />
                                                    </FormControl>
                                                    <FormMessage />
                                                    <FormDescription>
                                                        {t(
                                                            "clientNameDescription"
                                                        )}
                                                    </FormDescription>
                                                </FormItem>
                                            )}
                                        />
                                        <div className="flex items-center justify-end md:col-start-2">
                                            <Button
                                                type="button"
                                                variant="ghost"
                                                size="sm"
                                                onClick={() =>
                                                    setShowAdvancedSettings(
                                                        !showAdvancedSettings
                                                    )
                                                }
                                                className="flex items-center gap-2"
                                            >
                                                {showAdvancedSettings ? (
                                                    <ChevronUp className="h-4 w-4" />
                                                ) : (
                                                    <ChevronDown className="h-4 w-4" />
                                                )}
                                                {t("advancedSettings")}
                                            </Button>
                                        </div>
                                        {showAdvancedSettings && (
                                            <FormField
                                                control={form.control}
                                                name="subnet"
                                                render={({ field }) => (
                                                    <FormItem className="md:col-start-1 md:col-span-2">
                                                        <FormLabel>
                                                            {t("clientAddress")}
                                                        </FormLabel>
                                                        <FormControl>
                                                            <Input
                                                                autoComplete="off"
                                                                placeholder={t(
                                                                    "subnetPlaceholder"
                                                                )}
                                                                {...field}
                                                            />
                                                        </FormControl>
                                                        <FormMessage />
                                                        <FormDescription>
                                                            {t(
                                                                "addressDescription"
                                                            )}
                                                        </FormDescription>
                                                    </FormItem>
                                                )}
                                            />
                                        )}
                                    </form>
                                </Form>
                            </SettingsSectionBody>
                        </SettingsSection>

                        {form.watch("method") === "olm" && (
                            <>
                                <SettingsSection>
                                    <SettingsSectionHeader>
                                        <SettingsSectionTitle>
                                            {t("clientOlmCredentials")}
                                        </SettingsSectionTitle>
                                        <SettingsSectionDescription>
                                            {t(
                                                "clientOlmCredentialsDescription"
                                            )}
                                        </SettingsSectionDescription>
                                    </SettingsSectionHeader>
                                    <SettingsSectionBody>
                                        <InfoSections cols={3}>
                                            <InfoSection>
                                                <InfoSectionTitle>
                                                    {t("olmEndpoint")}
                                                </InfoSectionTitle>
                                                <InfoSectionContent>
                                                    <CopyToClipboard
                                                        text={
                                                            env.app.dashboardUrl
                                                        }
                                                    />
                                                </InfoSectionContent>
                                            </InfoSection>
                                            <InfoSection>
                                                <InfoSectionTitle>
                                                    {t("olmId")}
                                                </InfoSectionTitle>
                                                <InfoSectionContent>
                                                    <CopyToClipboard
                                                        text={olmId}
                                                    />
                                                </InfoSectionContent>
                                            </InfoSection>
                                            <InfoSection>
                                                <InfoSectionTitle>
                                                    {t("olmSecretKey")}
                                                </InfoSectionTitle>
                                                <InfoSectionContent>
                                                    <CopyToClipboard
                                                        text={olmSecret}
                                                    />
                                                </InfoSectionContent>
                                            </InfoSection>
                                        </InfoSections>
                                    </SettingsSectionBody>
                                </SettingsSection>
                                <OlmInstallCommands
                                    id={olmId}
                                    endpoint={env.app.dashboardUrl}
                                    secret={olmSecret}
                                    version={olmVersion}
                                />
                            </>
                        )}
                    </SettingsContainer>

                    <div className="flex justify-end space-x-2 mt-8">
                        <Button
                            type="button"
                            variant="outline"
                            onClick={() => {
                                router.push(`/${orgId}/settings/clients`);
                            }}
                        >
                            {t("cancel")}
                        </Button>
                        <Button
                            type="button"
                            loading={createLoading}
                            disabled={createLoading}
                            onClick={() => {
                                form.handleSubmit(onSubmit)();
                            }}
                        >
                            {t("createClient")}
                        </Button>
                    </div>
                </div>
            )}
        </>
    );
}
