import styles from "./agentCard.module.css";

import { useEffect, useRef, useState } from "react";

import { UserProfile, ModelOptions, UserConfig } from "@/app/common/auth";
import { Button } from "@/components/ui/button";

import {
    PaperPlaneTilt,
    Plus,
    Circle,
    Info,
    Check,
    ShieldWarning,
    Lock,
    Book,
    Brain,
    Waveform,
    CaretUpDown,
    Globe,
    LockOpen,
    FloppyDisk,
    DotsThreeVertical,
    Pencil,
    Trash,
    ArrowRight,
    ArrowLeft,
} from "@phosphor-icons/react";
import { z, ZodError } from "zod";
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import {
    Dialog,
    DialogContent,
    DialogFooter,
    DialogHeader,
    DialogTrigger,
} from "@/components/ui/dialog";
import LoginPrompt from "@/app/components/loginPrompt/loginPrompt";
import {
    getAvailableIcons,
    getIconForSlashCommand,
    getIconFromIconName,
} from "@/app/common/iconUtils";
import { convertColorToTextClass, tailwindColors } from "@/app/common/colorUtils";
import { Alert, AlertDescription } from "@/components/ui/alert";

import {
    Form,
    FormControl,
    FormDescription,
    FormField,
    FormItem,
    FormLabel,
    FormMessage,
} from "@/components/ui/form";
import { useForm, UseFormReturn } from "react-hook-form";
import { Input } from "@/components/ui/input";
import { zodResolver } from "@hookform/resolvers/zod";
import { Textarea } from "@/components/ui/textarea";
import {
    Select,
    SelectContent,
    SelectItem,
    SelectTrigger,
    SelectValue,
} from "@/components/ui/select";
import { DialogTitle } from "@radix-ui/react-dialog";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
import { cn } from "@/lib/utils";
import {
    Command,
    CommandEmpty,
    CommandGroup,
    CommandInput,
    CommandItem,
    CommandList,
} from "@/components/ui/command";
import { uploadDataForIndexing } from "@/app/common/chatFunctions";
import {
    AlertDialog,
    AlertDialogAction,
    AlertDialogCancel,
    AlertDialogContent,
    AlertDialogDescription,
    AlertDialogFooter,
    AlertDialogHeader,
    AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { Progress } from "@/components/ui/progress";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import ShareLink from "@/app/components/shareLink/shareLink";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";

export interface AgentData {
    slug: string;
    name: string;
    persona: string;
    color: string;
    icon: string;
    privacy_level: string;
    files?: string[];
    creator?: string;
    managed_by_admin: boolean;
    chat_model: string;
    input_tools: string[];
    output_modes: string[];
}

async function openChat(slug: string, userData: UserProfile | null) {
    const unauthenticatedRedirectUrl = `/login?next=/agents?agent=${slug}`;
    if (!userData) {
        window.location.href = unauthenticatedRedirectUrl;
        return;
    }

    const response = await fetch(`/api/chat/sessions?agent_slug=${encodeURIComponent(slug)}`, {
        method: "POST",
    });
    const data = await response.json();
    if (response.status == 200) {
        window.location.href = `/chat?conversationId=${data.conversation_id}`;
    } else if (response.status == 403 || response.status == 401) {
        window.location.href = unauthenticatedRedirectUrl;
    } else {
        alert("Failed to start chat session");
    }
}

function Badge(props: { icon: JSX.Element; text?: string; hoverText?: string }) {
    // Always convert text to proper case (e.g., "public" -> "Public")
    const displayBadgeText = props.text?.replace(/^\w/, (c) => c.toUpperCase()) || "";

    return (
        <TooltipProvider>
            <Tooltip>
                <TooltipContent asChild>
                    <div className="text-sm">{props.hoverText || displayBadgeText}</div>
                </TooltipContent>
                <TooltipTrigger className="cursor-text">
                    <div className="flex items-center space-x-2 rounded-full border-accent-500 border p-1.5">
                        <div className="text-muted-foreground">{props.icon}</div>
                        {displayBadgeText && displayBadgeText.length > 0 && (
                            <div className="text-muted-foreground text-sm">{displayBadgeText}</div>
                        )}
                    </div>
                </TooltipTrigger>
            </Tooltip>
        </TooltipProvider>
    );
}

export const EditAgentSchema = z.object({
    name: z.string({ required_error: "Name is required" }).min(1, "Name is required"),
    persona: z
        .string({ required_error: "Personality is required" })
        .min(1, "Personality is required"),
    color: z.string({ required_error: "Color is required" }).min(1, "Color is required"),
    icon: z.string({ required_error: "Icon is required" }).min(1, "Icon is required"),
    privacy_level: z
        .string({ required_error: "Privacy level is required" })
        .min(1, "Privacy level is required"),
    chat_model: z
        .string({ required_error: "Chat model is required" })
        .min(1, "Chat model is required"),
    files: z.array(z.string()).default([]).optional(),
    input_tools: z.array(z.string()).default([]).optional(),
    output_modes: z.array(z.string()).default([]).optional(),
});

interface AgentCardProps {
    data: AgentData;
    userProfile: UserProfile | null;
    isMobileWidth: boolean;
    editCard: boolean;
    showChatButton?: boolean;
    filesOptions: string[];
    modelOptions: ModelOptions[];
    selectedChatModelOption: string;
    isSubscribed: boolean;
    setAgentChangeTriggered: (value: boolean) => void;
    agentSlug: string;
    inputToolOptions: { [key: string]: string };
    outputModeOptions: { [key: string]: string };
}

export function AgentCard(props: AgentCardProps) {
    const [showModal, setShowModal] = useState(props.agentSlug === props.data.slug);
    const [showLoginPrompt, setShowLoginPrompt] = useState(false);
    const [errors, setErrors] = useState<string | null>(null);

    let lockIcon = <Lock />;
    let privacyHoverText = "Private agents are only visible to you.";

    if (props.data.privacy_level === "public") {
        lockIcon = <Globe />;
        privacyHoverText = "Public agents are visible to everyone.";
    } else if (props.data.privacy_level === "protected") {
        lockIcon = <LockOpen />;
        privacyHoverText = "Protected agents are visible to anyone with a direct link.";
    }

    const userData = props.userProfile;

    const form = useForm<z.infer<typeof EditAgentSchema>>({
        resolver: zodResolver(EditAgentSchema),
        defaultValues: {
            name: props.data.name,
            persona: props.data.persona,
            color: props.data.color,
            icon: props.data.icon,
            privacy_level: props.data.privacy_level,
            chat_model: props.data.chat_model,
            files: props.data.files,
            input_tools: props.data.input_tools,
            output_modes: props.data.output_modes,
        },
    });

    useEffect(() => {
        form.reset({
            name: props.data.name,
            persona: props.data.persona,
            color: props.data.color,
            icon: props.data.icon,
            privacy_level: props.data.privacy_level,
            chat_model: props.data.chat_model,
            files: props.data.files,
            input_tools: props.data.input_tools,
            output_modes: props.data.output_modes,
        });
    }, [props.data]);

    if (showModal) {
        window.history.pushState(
            {},
            `Khoj AI - Agent ${props.data.slug}`,
            `/agents?agent=${props.data.slug}`,
        );
    }

    const onSubmit = (values: z.infer<typeof EditAgentSchema>) => {
        let agentsApiUrl = `/api/agents`;
        let method = props.editCard ? "PATCH" : "POST";

        let valuesToSend: any = values;

        if (props.editCard) {
            valuesToSend = { ...values, slug: props.data.slug };
        }

        fetch(agentsApiUrl, {
            method: method,
            headers: {
                "Content-Type": "application/json",
            },
            body: JSON.stringify(valuesToSend),
        })
            .then((response) => {
                if (response.status === 200) {
                    form.reset();
                    setShowModal(false);
                    setErrors(null);
                    props.setAgentChangeTriggered(true);
                } else {
                    response.json().then((data) => {
                        console.error(data);
                        form.clearErrors();
                        if (data.error) {
                            setErrors(data.error);
                        }
                    });
                }
            })
            .catch((error) => {
                console.error("Error:", error);
                setErrors(error);
                form.clearErrors();
            });
    };

    const stylingString = convertColorToTextClass(props.data.color);

    function makeBadgeFooter() {
        return (
            <div className="flex flex-wrap items-center gap-1">
                {props.editCard && (
                    <Badge
                        icon={lockIcon}
                        text={props.data.privacy_level}
                        hoverText={privacyHoverText}
                    />
                )}
                {props.data.files && props.data.files.length > 0 && (
                    <Badge
                        icon={<Book />}
                        text={`knowledge`}
                        hoverText={`The agent has a custom knowledge base with ${props.data.files.length} documents. It can use them to give you answers.`}
                    />
                )}
                <Badge
                    icon={<Brain />}
                    text={props.data.chat_model}
                    hoverText={`The agent uses the ${props.data.chat_model} model to chat with you.`}
                />
                {props.data.output_modes.map((outputMode) => (
                    <Badge
                        key={outputMode}
                        icon={getIconForSlashCommand(outputMode)}
                        hoverText={`${outputMode}: ${props.outputModeOptions[outputMode]}`}
                    />
                ))}
                {props.data.input_tools.map((inputTool) => (
                    <Badge
                        key={inputTool}
                        icon={getIconForSlashCommand(inputTool)}
                        hoverText={`${inputTool}: ${props.inputToolOptions[inputTool]}`}
                    />
                ))}
            </div>
        );
    }

    return (
        <Card
            className={`shadow-sm bg-gradient-to-b from-white 20% to-${props.data.color ? props.data.color : "gray"}-100/50 dark:from-[hsl(var(--background))] dark:to-${props.data.color ? props.data.color : "gray"}-950/50 rounded-xl hover:shadow-md`}
        >
            {showLoginPrompt && (
                <LoginPrompt
                    loginRedirectMessage={`Sign in to start chatting with ${props.data.name}`}
                    onOpenChange={setShowLoginPrompt}
                />
            )}
            <CardHeader>
                <CardTitle>
                    <Dialog
                        open={showModal}
                        onOpenChange={() => {
                            setShowModal(!showModal);
                            window.history.pushState({}, `Khoj AI - Agents`, `/agents`);
                        }}
                    >
                        <DialogTrigger className="focus-visible:outline-none">
                            <div className="flex items-center relative top-2">
                                {getIconFromIconName(props.data.icon, props.data.color)}
                                {props.data.name}
                            </div>
                        </DialogTrigger>
                        <div className="flex float-right">
                            {props.editCard && (
                                <div className="float-right">
                                    <Popover>
                                        <PopoverTrigger>
                                            <Button
                                                className={`bg-[hsl(var(--background))] w-10 h-10 p-0 rounded-xl border dark:border-neutral-700 shadow-sm hover:bg-stone-100 dark:hover:bg-neutral-900`}
                                            >
                                                <DotsThreeVertical
                                                    className={`w-6 h-6 ${convertColorToTextClass(props.data.color)}`}
                                                />
                                            </Button>
                                        </PopoverTrigger>
                                        <PopoverContent
                                            className="w-fit grid p-1"
                                            side={"bottom"}
                                            align={"end"}
                                        >
                                            <Button
                                                className="items-center justify-start"
                                                variant={"ghost"}
                                                onClick={() => setShowModal(true)}
                                            >
                                                <Pencil className="w-4 h-4 mr-2" />
                                                Edit
                                            </Button>
                                            {props.editCard &&
                                                props.data.privacy_level !== "private" && (
                                                    <ShareLink
                                                        buttonTitle="Share"
                                                        title="Share Agent"
                                                        description="Share a link to this agent with others. They'll be able to chat with it, and ask questions to all of its knowledge base."
                                                        buttonVariant={"ghost" as const}
                                                        includeIcon={true}
                                                        url={`${window.location.origin}/agents?agent=${props.data.slug}`}
                                                    />
                                                )}
                                            {props.data.creator === userData?.username && (
                                                <Button
                                                    className="items-center justify-start"
                                                    variant={"destructive"}
                                                    onClick={() => {
                                                        fetch(`/api/agents/${props.data.slug}`, {
                                                            method: "DELETE",
                                                        }).then(() => {
                                                            props.setAgentChangeTriggered(true);
                                                        });
                                                    }}
                                                >
                                                    <Trash className="w-4 h-4 mr-2" />
                                                    Delete
                                                </Button>
                                            )}
                                        </PopoverContent>
                                    </Popover>
                                </div>
                            )}
                            {(props.showChatButton ?? true) && (
                                <div className="float-right">
                                    {props.userProfile ? (
                                        <Button
                                            className={`bg-[hsl(var(--background))] w-10 h-10 p-0 rounded-xl border dark:border-neutral-700 shadow-sm hover:bg-stone-100 dark:hover:bg-neutral-900`}
                                            onClick={() => openChat(props.data.slug, userData)}
                                        >
                                            <PaperPlaneTilt
                                                className={`w-6 h-6 ${convertColorToTextClass(props.data.color)}`}
                                            />
                                        </Button>
                                    ) : (
                                        <Button
                                            className={`bg-[hsl(var(--background))] w-14 h-14 rounded-xl border dark:border-neutral-700 shadow-sm hover:bg-stone-100 dark:hover:bg-neutral-900`}
                                            onClick={() => setShowLoginPrompt(true)}
                                        >
                                            <PaperPlaneTilt
                                                className={`w-6 h-6 ${convertColorToTextClass(props.data.color)}`}
                                            />
                                        </Button>
                                    )}
                                </div>
                            )}
                        </div>
                        {props.editCard ? (
                            <DialogContent
                                className={"lg:max-w-screen-lg overflow-y-scroll max-h-screen"}
                            >
                                <DialogTitle>
                                    Edit <b>{props.data.name}</b>
                                </DialogTitle>
                                <AgentModificationForm
                                    form={form}
                                    onSubmit={onSubmit}
                                    create={false}
                                    errors={errors}
                                    filesOptions={props.filesOptions}
                                    modelOptions={props.modelOptions}
                                    slug={props.data.slug}
                                    inputToolOptions={props.inputToolOptions}
                                    isSubscribed={props.isSubscribed}
                                    outputModeOptions={props.outputModeOptions}
                                />
                            </DialogContent>
                        ) : (
                            <DialogContent className="whitespace-pre-line max-h-[80vh] max-w-[90vw] rounded-lg">
                                <DialogHeader>
                                    <div className="flex items-center">
                                        {getIconFromIconName(props.data.icon, props.data.color)}
                                        <p className="font-bold text-lg">{props.data.name}</p>
                                    </div>
                                </DialogHeader>
                                <div className="max-h-[60vh] overflow-y-scroll text-neutral-500 dark:text-white">
                                    {props.data.persona}
                                </div>
                                <div className="flex flex-wrap items-center gap-1">
                                    {makeBadgeFooter()}
                                </div>
                                <DialogFooter>
                                    <Button
                                        className={`pt-6 pb-6 ${stylingString} bg-white dark:bg-[hsl(var(--background))] text-neutral-500 dark:text-white border-2 border-stone-100 shadow-sm rounded-xl hover:bg-stone-100 dark:hover:bg-neutral-900 dark:border-neutral-700`}
                                        onClick={() => {
                                            openChat(props.data.slug, userData);
                                            setShowModal(false);
                                        }}
                                    >
                                        <PaperPlaneTilt
                                            className={`w-6 h-6 m-2 ${convertColorToTextClass(props.data.color)}`}
                                        />
                                        Start Chatting
                                    </Button>
                                </DialogFooter>
                            </DialogContent>
                        )}
                    </Dialog>
                </CardTitle>
            </CardHeader>
            <CardContent>
                <div className={styles.agentPersonality}>
                    <button
                        className={`${styles.infoButton} text-neutral-500 dark:text-white`}
                        onClick={() => setShowModal(true)}
                    >
                        <p>{props.data.persona}</p>
                    </button>
                </div>
            </CardContent>
            <CardFooter>
                <div className="flex flex-wrap items-center gap-1">{makeBadgeFooter()}</div>
            </CardFooter>
        </Card>
    );
}

interface AgentModificationFormProps {
    form: UseFormReturn<z.infer<typeof EditAgentSchema>>;
    onSubmit: (values: z.infer<typeof EditAgentSchema>) => void;
    userConfig?: UserConfig;
    create?: boolean;
    errors?: string | null;
    modelOptions: ModelOptions[];
    filesOptions: string[];
    inputToolOptions: { [key: string]: string };
    outputModeOptions: { [key: string]: string };
    slug?: string;
    isSubscribed: boolean;
}

export function AgentModificationForm(props: AgentModificationFormProps) {
    const [isSaving, setIsSaving] = useState(false);

    const iconOptions = getAvailableIcons();
    const colorOptions = tailwindColors;
    const colorOptionClassName = convertColorToTextClass(props.form.getValues("color"));

    const [isDragAndDropping, setIsDragAndDropping] = useState(false);
    const [warning, setWarning] = useState<string | null>(null);
    const [error, setError] = useState<string | null>(null);
    const [uploading, setUploading] = useState(false);
    const [progressValue, setProgressValue] = useState(0);
    const [uploadedFiles, setUploadedFiles] = useState<string[]>([]);
    const [allFileOptions, setAllFileOptions] = useState<string[]>([]);
    const [currentStep, setCurrentStep] = useState(0);

    const [showSubscribeDialog, setShowSubscribeDialog] = useState(true);

    const privacyOptions = ["public", "private", "protected"];

    const basicFields = [
        { name: "name", label: "Name" },
        { name: "persona", label: "Personality" },
    ];

    const advancedFields = [
        { name: "files", label: "Knowledge Base" },
        { name: "input_tools", label: "Input Tools" },
        { name: "output_modes", label: "Output Modes" },
    ];

    const customizationFields = [
        { name: "color", label: "Color" },
        { name: "icon", label: "Icon" },
        { name: "chat_model", label: "Chat Model" },
        { name: "privacy_level", label: "Privacy Level" },
    ];

    const formGroups = [
        { fields: basicFields, label: "Basic Settings" },
        { fields: customizationFields, label: "Customization & Access" },
        { fields: advancedFields, label: "Advanced Settings" },
    ];

    const fileInputRef = useRef<HTMLInputElement>(null);

    useEffect(() => {
        if (!uploading) {
            setProgressValue(0);
        }

        if (uploading) {
            const interval = setInterval(() => {
                setProgressValue((prev) => {
                    const increment = Math.floor(Math.random() * 5) + 1; // Generates a random number between 1 and 5
                    const nextValue = prev + increment;
                    return nextValue < 100 ? nextValue : 100; // Ensures progress does not exceed 100
                });
            }, 800);
            return () => clearInterval(interval);
        }
    }, [uploading]);

    useEffect(() => {
        const currentFiles = props.form.getValues("files") || [];
        const fileOptions = props.filesOptions || [];
        const concatenatedFiles = [...currentFiles, ...fileOptions];
        const fullAllFileOptions = [...allFileOptions, ...concatenatedFiles];
        const dedupedAllFileOptions = Array.from(new Set(fullAllFileOptions));
        setAllFileOptions(dedupedAllFileOptions);
    }, []);

    useEffect(() => {
        if (uploadedFiles.length > 0) {
            handleAgentFileChange(uploadedFiles);
            setAllFileOptions((prev) => [...prev, ...uploadedFiles]);
        }
    }, [uploadedFiles]);

    useEffect(() => {
        if (props.errors) {
            setIsSaving(false);
        }
    }, [props.errors]);

    function handleDragOver(event: React.DragEvent<HTMLDivElement>) {
        event.preventDefault();
        setIsDragAndDropping(true);
    }

    function handleDragLeave(event: React.DragEvent<HTMLDivElement>) {
        event.preventDefault();
        setIsDragAndDropping(false);
    }

    function handleDragAndDropFiles(event: React.DragEvent<HTMLDivElement>) {
        event.preventDefault();
        setIsDragAndDropping(false);

        if (!event.dataTransfer.files) return;

        uploadFiles(event.dataTransfer.files);
    }

    function uploadFiles(files: FileList) {
        uploadDataForIndexing(files, setWarning, setUploading, setError, setUploadedFiles);
    }

    function openFileInput() {
        if (fileInputRef && fileInputRef.current) {
            fileInputRef.current.click();
        }
    }

    function handleFileChange(event: React.ChangeEvent<HTMLInputElement>) {
        if (!event.target.files) return;

        uploadFiles(event.target.files);
    }

    const handleNext = (event: React.MouseEvent<HTMLButtonElement>) => {
        event.preventDefault();
        if (currentStep < formGroups.length - 1) {
            setCurrentStep(currentStep + 1);
        }
    };

    const handlePrevious = (event: React.MouseEvent<HTMLButtonElement>) => {
        event.preventDefault();
        if (currentStep > 0) {
            setCurrentStep(currentStep - 1);
        }
    };

    const handleSubmit = (values: any) => {
        props.onSubmit(values);
        setIsSaving(true);
    };

    const handleAgentFileChange = (files: string[]) => {
        for (const file of files) {
            const currentFiles = props.form.getValues("files") || [];
            const newFiles = currentFiles.includes(file)
                ? currentFiles.filter((item) => item !== file)
                : [...currentFiles, file];
            props.form.setValue("files", newFiles);
        }
    };

    const areRequiredFieldsCompletedForCurrentStep = (formGroup: {
        fields: { name: string }[];
    }) => {
        try {
            EditAgentSchema.parse(props.form.getValues());
            return true;
        } catch (error) {
            const errors: { [key: string]: string } = (error as ZodError).errors.reduce(
                (acc: any, curr: any) => {
                    acc[curr.path[0]] = curr.message;
                    return acc;
                },
                {},
            );

            for (const field of formGroup.fields) {
                if (errors[field.name]) {
                    return false;
                }
            }

            return true;
        }
    };

    if (!props.isSubscribed && showSubscribeDialog) {
        return (
            <AlertDialog open={true}>
                <AlertDialogContent>
                    <AlertDialogHeader>
                        <AlertDialogTitle>Upgrade to Futurist</AlertDialogTitle>
                    </AlertDialogHeader>
                    <AlertDialogDescription>
                        You need to be a Futurist subscriber to create more agents.{" "}
                        <a href="/settings">Upgrade now</a>.
                    </AlertDialogDescription>
                    <AlertDialogFooter>
                        <AlertDialogCancel
                            onClick={() => {
                                setShowSubscribeDialog(false);
                            }}
                        >
                            Cancel
                        </AlertDialogCancel>
                        <AlertDialogAction
                            onClick={() => {
                                window.location.href = "/settings";
                            }}
                        >
                            Continue
                        </AlertDialogAction>
                    </AlertDialogFooter>
                </AlertDialogContent>
            </AlertDialog>
        );
    }

    const renderFormField = (fieldName: string) => {
        switch (fieldName) {
            case "name":
                return (
                    <FormField
                        key={fieldName}
                        control={props.form.control}
                        name="name"
                        render={({ field }) => (
                            <FormItem className="space-y-0 grid gap-2">
                                <FormLabel>Name</FormLabel>
                                <FormDescription>
                                    What should this agent be called? Pick something descriptive &
                                    memorable.
                                </FormDescription>
                                <FormControl>
                                    <Input placeholder="Biologist" {...field} />
                                </FormControl>
                                <FormMessage />
                            </FormItem>
                        )}
                    />
                );
            case "chat_model":
                return (
                    <FormField
                        key={fieldName}
                        control={props.form.control}
                        name="chat_model"
                        render={({ field }) => (
                            <FormItem className="space-y-1 grid gap-2">
                                <FormLabel>Chat Model</FormLabel>
                                <FormDescription>
                                    Which large language model should this agent use?
                                </FormDescription>
                                <Select onValueChange={field.onChange} defaultValue={field.value}>
                                    <FormControl>
                                        <SelectTrigger className="text-left">
                                            <SelectValue />
                                        </SelectTrigger>
                                    </FormControl>
                                    <SelectContent className="items-start space-y-1 inline-flex flex-col">
                                        {props.modelOptions.map((modelOption) => (
                                            <SelectItem
                                                key={modelOption.id}
                                                value={modelOption.name}
                                            >
                                                <div className="flex items-center space-x-2">
                                                    {modelOption.name}
                                                </div>
                                            </SelectItem>
                                        ))}
                                    </SelectContent>
                                </Select>
                                <FormMessage />
                            </FormItem>
                        )}
                    />
                );
            case "privacy_level":
                return (
                    <FormField
                        key={fieldName}
                        control={props.form.control}
                        name="privacy_level"
                        render={({ field }) => (
                            <FormItem className="space-y-1 grid gap-2">
                                <FormLabel>
                                    <div>Privacy Level</div>
                                </FormLabel>
                                <FormDescription>
                                    <Popover>
                                        <PopoverTrigger asChild>
                                            <Button
                                                variant={"ghost" as const}
                                                className="p-0 h-fit"
                                            >
                                                <span className="items-center flex gap-1 text-sm">
                                                    <Info className="inline" />
                                                    <p className="text-sm">Learn more</p>
                                                </span>
                                            </Button>
                                        </PopoverTrigger>
                                        <PopoverContent>
                                            <b>Private</b>: only visible to you.
                                            <br />
                                            <b>Protected</b>: visible to anyone with a link.
                                            <br />
                                            <b>Public</b>: visible to everyone.
                                            <br />
                                            All public agents will be reviewed by us before they are
                                            launched.
                                        </PopoverContent>
                                    </Popover>
                                </FormDescription>
                                <Select onValueChange={field.onChange} defaultValue={field.value}>
                                    <FormControl>
                                        <SelectTrigger className="w-[200px]">
                                            <SelectValue placeholder="private" />
                                        </SelectTrigger>
                                    </FormControl>
                                    <SelectContent className="items-center space-y-1 inline-flex flex-col">
                                        {privacyOptions.map((privacyOption) => (
                                            <SelectItem key={privacyOption} value={privacyOption}>
                                                <div className="flex items-center space-x-2">
                                                    {privacyOption}
                                                </div>
                                            </SelectItem>
                                        ))}
                                    </SelectContent>
                                </Select>
                                <FormMessage />
                            </FormItem>
                        )}
                    />
                );
            case "color":
                return (
                    <FormField
                        key={fieldName}
                        control={props.form.control}
                        name="color"
                        render={({ field }) => (
                            <FormItem className="space-y-3">
                                <FormLabel>Color</FormLabel>
                                <FormDescription>Choose a color for your agent.</FormDescription>
                                <Select onValueChange={field.onChange} defaultValue={field.value}>
                                    <FormControl>
                                        <SelectTrigger className="w-[200px]">
                                            <SelectValue placeholder="Color" />
                                        </SelectTrigger>
                                    </FormControl>
                                    <SelectContent className="items-center space-y-1 inline-flex flex-col">
                                        {colorOptions.map((colorOption) => (
                                            <SelectItem key={colorOption} value={colorOption}>
                                                <div className="flex items-center space-x-2">
                                                    <Circle
                                                        className={`w-6 h-6 mr-2 ${convertColorToTextClass(colorOption)}`}
                                                        weight="fill"
                                                    />
                                                    {colorOption}
                                                </div>
                                            </SelectItem>
                                        ))}
                                    </SelectContent>
                                </Select>
                                <FormMessage />
                            </FormItem>
                        )}
                    />
                );
            case "icon":
                return (
                    <FormField
                        key={fieldName}
                        control={props.form.control}
                        name="icon"
                        render={({ field }) => (
                            <FormItem className="space-y-3">
                                <FormLabel>Icon</FormLabel>
                                <FormDescription>Choose an icon for your agent.</FormDescription>
                                <Select onValueChange={field.onChange} defaultValue={field.value}>
                                    <FormControl>
                                        <SelectTrigger className="w-[200px]">
                                            <SelectValue placeholder="Icon" />
                                        </SelectTrigger>
                                    </FormControl>
                                    <SelectContent className="items-center space-y-1 inline-flex flex-col">
                                        {iconOptions.map((iconOption) => (
                                            <SelectItem key={iconOption} value={iconOption}>
                                                <div className="flex items-center space-x-2">
                                                    {getIconFromIconName(
                                                        iconOption,
                                                        props.form.getValues("color"),
                                                        "w-6",
                                                        "h-6",
                                                    )}
                                                    {iconOption}
                                                </div>
                                            </SelectItem>
                                        ))}
                                    </SelectContent>
                                </Select>
                                <FormMessage />
                            </FormItem>
                        )}
                    />
                );
            case "persona":
                return (
                    <FormField
                        key={fieldName}
                        control={props.form.control}
                        name="persona"
                        render={({ field }) => (
                            <FormItem className="space-y-1 grid gap-2">
                                <FormLabel>Personality</FormLabel>
                                <FormDescription>
                                    What is the personality, thought process, or tuning of this
                                    agent? Get creative; this is how you can influence the agent
                                    constitution.
                                </FormDescription>
                                <FormControl>
                                    <Textarea
                                        placeholder="You are an excellent biologist, at the top of your field in marine biology."
                                        {...field}
                                    />
                                </FormControl>
                                <FormMessage />
                            </FormItem>
                        )}
                    />
                );
            case "files":
                return (
                    <FormField
                        key={fieldName}
                        control={props.form.control}
                        name="files"
                        render={({ field }) => (
                            <FormItem className="flex flex-col gap-2">
                                <FormLabel>Knowledge Base</FormLabel>
                                <FormDescription>
                                    Which information should be part of its digital brain?{" "}
                                    <a href="/settings">Manage data</a>.
                                </FormDescription>
                                <Collapsible>
                                    <CollapsibleTrigger className="flex items-center justify-between text-sm gap-2">
                                        <CaretUpDown />
                                        {field.value && field.value.length > 0
                                            ? `${field.value.length} files selected`
                                            : "Select files"}
                                    </CollapsibleTrigger>
                                    <CollapsibleContent>
                                        <Command>
                                            <AlertDialog open={warning !== null || error != null}>
                                                <AlertDialogContent>
                                                    <AlertDialogHeader>
                                                        <AlertDialogTitle>Alert</AlertDialogTitle>
                                                    </AlertDialogHeader>
                                                    <AlertDialogDescription>
                                                        {warning || error}
                                                    </AlertDialogDescription>
                                                    <AlertDialogAction
                                                        className="bg-slate-400 hover:bg-slate-500"
                                                        onClick={() => {
                                                            setWarning(null);
                                                            setError(null);
                                                            setUploading(false);
                                                        }}
                                                    >
                                                        Close
                                                    </AlertDialogAction>
                                                </AlertDialogContent>
                                            </AlertDialog>
                                            <div
                                                className={`flex flex-col h-full cursor-pointer`}
                                                onDragOver={handleDragOver}
                                                onDragLeave={handleDragLeave}
                                                onDrop={handleDragAndDropFiles}
                                                onClick={openFileInput}
                                            >
                                                <input
                                                    type="file"
                                                    multiple
                                                    ref={fileInputRef}
                                                    style={{ display: "none" }}
                                                    onChange={handleFileChange}
                                                />
                                                <div className="flex-none p-4">
                                                    {uploading && (
                                                        <Progress
                                                            indicatorColor="bg-slate-500"
                                                            className="w-full h-2 rounded-full"
                                                            value={progressValue}
                                                        />
                                                    )}
                                                </div>
                                                <div
                                                    className={`flex-none p-4 bg-secondary border-b ${isDragAndDropping ? "animate-pulse" : ""} rounded-lg`}
                                                >
                                                    <div className="flex items-center justify-center w-full h-16 border-2 border-dashed border-gray-300 rounded-lg">
                                                        {isDragAndDropping ? (
                                                            <div className="flex items-center justify-center w-full h-full">
                                                                <Waveform className="h-6 w-6 mr-2" />
                                                                <span>Drop files to upload</span>
                                                            </div>
                                                        ) : (
                                                            <div className="flex items-center justify-center w-full h-full">
                                                                <Plus className="h-6 w-6 mr-2" />
                                                                <span>
                                                                    Drag and drop files here
                                                                </span>
                                                            </div>
                                                        )}
                                                    </div>
                                                </div>
                                            </div>
                                            <CommandInput placeholder="Select files..." />
                                            <CommandList>
                                                <CommandEmpty>No files found.</CommandEmpty>
                                                <CommandGroup>
                                                    {allFileOptions.map((file) => (
                                                        <CommandItem
                                                            value={file}
                                                            key={file}
                                                            onSelect={() => {
                                                                const currentFiles =
                                                                    props.form.getValues("files") ||
                                                                    [];
                                                                const newFiles =
                                                                    currentFiles.includes(file)
                                                                        ? currentFiles.filter(
                                                                              (item) =>
                                                                                  item !== file,
                                                                          )
                                                                        : [...currentFiles, file];
                                                                props.form.setValue(
                                                                    "files",
                                                                    newFiles,
                                                                );
                                                            }}
                                                        >
                                                            <Check
                                                                className={cn(
                                                                    "mr-2 h-4 w-4",
                                                                    field.value &&
                                                                        field.value.includes(file)
                                                                        ? "opacity-100"
                                                                        : "opacity-0",
                                                                )}
                                                            />
                                                            {file}
                                                        </CommandItem>
                                                    ))}
                                                </CommandGroup>
                                            </CommandList>
                                        </Command>
                                    </CollapsibleContent>
                                </Collapsible>
                            </FormItem>
                        )}
                    />
                );
            case "input_tools":
                return (
                    <FormField
                        key={fieldName}
                        control={props.form.control}
                        name="input_tools"
                        render={({ field }) => (
                            <FormItem className="flex flex-col gap-2">
                                <FormLabel>Restrict Input Tools</FormLabel>
                                <FormDescription>
                                    Which knowledge retrieval tools should this agent be limited to?
                                    <br />
                                    <b>Default:</b> No limitations.
                                </FormDescription>
                                <Collapsible>
                                    <CollapsibleTrigger className="flex items-center justify-between text-sm gap-2">
                                        <CaretUpDown />
                                        {field.value && field.value.length > 0
                                            ? `${field.value.length} tools selected`
                                            : "All tools"}
                                    </CollapsibleTrigger>
                                    <CollapsibleContent>
                                        <Command>
                                            <CommandList>
                                                <CommandGroup>
                                                    {Object.entries(props.inputToolOptions).map(
                                                        ([key, value]) => (
                                                            <CommandItem
                                                                value={key}
                                                                key={key}
                                                                onSelect={() => {
                                                                    const currentInputTools =
                                                                        props.form.getValues(
                                                                            "input_tools",
                                                                        ) || [];
                                                                    const newInputTools =
                                                                        currentInputTools.includes(
                                                                            key,
                                                                        )
                                                                            ? currentInputTools.filter(
                                                                                  (item) =>
                                                                                      item !== key,
                                                                              )
                                                                            : [
                                                                                  ...currentInputTools,
                                                                                  key,
                                                                              ];
                                                                    props.form.setValue(
                                                                        "input_tools",
                                                                        newInputTools,
                                                                    );
                                                                }}
                                                            >
                                                                <Check
                                                                    className={cn(
                                                                        "mr-2 h-4 w-4",
                                                                        field.value &&
                                                                            field.value.includes(
                                                                                key,
                                                                            )
                                                                            ? "opacity-100"
                                                                            : "opacity-0",
                                                                    )}
                                                                />
                                                                <div
                                                                    className={cn(
                                                                        "flex items-center space-x-2",
                                                                    )}
                                                                >
                                                                    <p>
                                                                        <b>{key}</b>
                                                                    </p>
                                                                    <p>{value}</p>
                                                                </div>
                                                            </CommandItem>
                                                        ),
                                                    )}
                                                </CommandGroup>
                                            </CommandList>
                                        </Command>
                                    </CollapsibleContent>
                                </Collapsible>
                            </FormItem>
                        )}
                    />
                );
            case "output_modes":
                return (
                    <FormField
                        key={fieldName}
                        control={props.form.control}
                        name="output_modes"
                        render={({ field }) => (
                            <FormItem className="flex flex-col gap-2">
                                <FormLabel>Restrict Output Modes</FormLabel>
                                <FormDescription>
                                    Which output modes should this agent be limited to?
                                    <br />
                                    <b>Default:</b> No limitations.
                                </FormDescription>
                                <Collapsible>
                                    <CollapsibleTrigger className="flex items-center justify-between text-sm gap-2">
                                        <CaretUpDown />
                                        {field.value && field.value.length > 0
                                            ? `${field.value.length} modes selected`
                                            : "All modes"}
                                    </CollapsibleTrigger>
                                    <CollapsibleContent>
                                        <Command>
                                            <CommandList>
                                                <CommandGroup>
                                                    {Object.entries(props.outputModeOptions).map(
                                                        ([key, value]) => (
                                                            <CommandItem
                                                                value={key}
                                                                key={key}
                                                                onSelect={() => {
                                                                    const currentOutputModes =
                                                                        props.form.getValues(
                                                                            "output_modes",
                                                                        ) || [];
                                                                    const newOutputModes =
                                                                        currentOutputModes.includes(
                                                                            key,
                                                                        )
                                                                            ? currentOutputModes.filter(
                                                                                  (item) =>
                                                                                      item !== key,
                                                                              )
                                                                            : [
                                                                                  ...currentOutputModes,
                                                                                  key,
                                                                              ];
                                                                    props.form.setValue(
                                                                        "output_modes",
                                                                        newOutputModes,
                                                                    );
                                                                }}
                                                            >
                                                                <Check
                                                                    className={cn(
                                                                        "mr-2 h-4 w-4",
                                                                        field.value &&
                                                                            field.value.includes(
                                                                                key,
                                                                            )
                                                                            ? "opacity-100"
                                                                            : "opacity-0",
                                                                    )}
                                                                />
                                                                <div
                                                                    className={cn(
                                                                        "flex items-center space-x-2",
                                                                    )}
                                                                >
                                                                    <p>
                                                                        <b>{key}</b>
                                                                    </p>
                                                                    <p>{value}</p>
                                                                </div>
                                                            </CommandItem>
                                                        ),
                                                    )}
                                                </CommandGroup>
                                            </CommandList>
                                        </Command>
                                    </CollapsibleContent>
                                </Collapsible>
                            </FormItem>
                        )}
                    />
                );
            default:
                return null;
        }
    };

    return (
        <Form {...props.form}>
            <form onSubmit={props.form.handleSubmit(handleSubmit)} className="space-y-6">
                <div className="space-y-6">{formGroups[currentStep].label}</div>
                {currentStep < formGroups.length &&
                    formGroups[currentStep].fields.map((field) => renderFormField(field.name))}
                <div className="flex justify-between mt-4">
                    <Button
                        type="button"
                        variant={"outline"}
                        onClick={handlePrevious}
                        disabled={currentStep === 0}
                        className={`items-center ${isSaving ? "bg-stone-100 dark:bg-neutral-900" : ""} text-white ${colorOptionClassName}`}
                    >
                        <ArrowLeft className="mr-2 h-4 w-4" />
                        Previous
                    </Button>
                    {currentStep < formGroups.length - 1 ? (
                        <Button
                            type="button"
                            variant={"outline"}
                            onClick={handleNext}
                            disabled={
                                !areRequiredFieldsCompletedForCurrentStep(formGroups[currentStep])
                            }
                            className={`items-center ${isSaving ? "bg-stone-100 dark:bg-neutral-900" : ""} text-white ${colorOptionClassName}`}
                        >
                            Next
                            <ArrowRight className="ml-2 h-4 w-4" />
                        </Button>
                    ) : (
                        <Button
                            type="submit"
                            variant={"outline"}
                            disabled={isSaving || !props.isSubscribed}
                            className={`items-center ${isSaving ? "bg-stone-100 dark:bg-neutral-900" : ""} text-white ${colorOptionClassName}`}
                        >
                            <FloppyDisk className="h-4 w-4 mr-2" />
                            {isSaving ? "Booting..." : "Save"}
                        </Button>
                    )}
                </div>

                {props.errors && (
                    <Alert className="bg-secondary border-none my-4">
                        <AlertDescription className="flex items-center gap-1">
                            <ShieldWarning
                                weight="fill"
                                className="h-4 w-4 text-yellow-400 inline"
                            />
                            <span>{props.errors}</span>
                        </AlertDescription>
                    </Alert>
                )}
            </form>
        </Form>
    );
}
