"use client";

import * as React from "react";

import Link from "next/link";

import { z } from "zod";
import { useForm, UseFormReturn } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";

import { useMutation, useQueryClient } from "@tanstack/react-query";

import axios from "axios";

import { Braces, Check, Code, MessageCircle } from "lucide-react";

import { toast } from "sonner";
import confetti from "canvas-confetti";
import { defineStepper, Stepper } from "@stepperize/react";

import { createAgentSchema } from "../schemas/create-agent-schema";

import { cn } from "@/lib/utils";
import { Tables } from "@/utils/supabase/database.types";
import { createClient } from "@/utils/supabase/client";

import { Button, buttonVariants } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator";

import CardBackground from "@/components/card-background";
import AgentForm from "./agent-form";

const data = [
  {
    id: "agentType",
    title: "Agent Type",
    description: "Select how your Agent will interact",
  },
  {
    id: "agentForm",
    title: "Agent Form",
    description: "Enter your agent informations",
  },
  { id: "complete", title: "Complete", description: "Checkout complete" },
];

const { useStepper, steps, utils } = defineStepper(...data);

const triggerConfetti = () => {
  const duration = 5 * 1000;
  const animationEnd = Date.now() + duration;
  const defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 0 };

  const randomInRange = (min: number, max: number) =>
    Math.random() * (max - min) + min;

  const interval = window.setInterval(() => {
    const timeLeft = animationEnd - Date.now();

    if (timeLeft <= 0) {
      return clearInterval(interval);
    }

    const particleCount = 50 * (timeLeft / duration);
    confetti({
      ...defaults,
      particleCount,
      origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 },
    });
    confetti({
      ...defaults,
      particleCount,
      origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 },
    });
  }, 250);
};

export default function FormStepper() {
  const [agentId, setAgentId] = React.useState("");
  const [agentName, setAgenName] = React.useState("");

  const stepper = useStepper();

  const currentIndex = utils.getIndex(stepper.current.id);

  const form = useForm<z.infer<typeof createAgentSchema>>({
    resolver: zodResolver(createAgentSchema),
    defaultValues: {
      userId: "",
      name: "",
      description: "",
      modelType: "general",
    },
    mode: "onChange",
  });

  const queryClient = useQueryClient();

  const createAgentMutation = useMutation({
    mutationFn: async (values: z.infer<typeof createAgentSchema>) => {
      const { modelType, userId, ...rest } = values;

      const supabase = createClient();

      const url = encodeURI(
        `https://ai-endpoint-one.dev3vds1.link/ai-image/${values.description}`
      );

      const json = await axios.get(url);

      const response = await supabase
        .from("agents")
        .insert({
          ...rest,
          model_type: "general",
          image_url: json.data.url,
          user_id: userId,
          conversation: 0,
          last_conv: null,
        })
        .select()
        .limit(1)
        .single();

      if (response.error) throw new Error(response.error.message);

      return response.data;
    },
    onSuccess: (data: Tables<"agents">) => {
      queryClient.invalidateQueries({
        queryKey: ["agents"],
      });
      triggerConfetti();
      stepper.next();

      setAgentId(data.id.toString());
      setAgenName(data.name);

      stepper.next();
    },
    onError: (err) => {
      toast.error(err.message);
    },
  });

  const handleSubmit = (values: z.infer<typeof createAgentSchema>) => {
    createAgentMutation.mutate(values);
  };

  return (
    <CardBackground>
      {/* form title  */}
      <div className="flex justify-between mb-6">
        <div>
          <h2 className="text-primary text-lg font-bold mb-1">Agent Form</h2>
          <p className="text-sm text-muted-foreground">
            {stepper.current.description}
          </p>
        </div>
        <div className="flex items-center gap-2">
          <span className="text-sm text-muted-foreground">
            Step {currentIndex + 1} of {steps.length}
          </span>
          <div />
        </div>
      </div>
      {/* form nav  */}
      <nav aria-label="Checkout Steps" className="group mb-6">
        <ol
          className="flex items-center justify-between gap-2"
          aria-orientation="horizontal"
        >
          {stepper.all.map((step, index, array) => (
            <React.Fragment key={step.id}>
              <li className="flex items-center gap-4 flex-shrink-0">
                <Button
                  type="button"
                  role="tab"
                  variant={index <= currentIndex ? "default" : "outline"}
                  aria-current={
                    stepper.current.id === step.id ? "step" : undefined
                  }
                  aria-posinset={index + 1}
                  aria-setsize={steps.length}
                  aria-selected={stepper.current.id === step.id}
                  className="flex size-10 items-center justify-center rounded-full"
                >
                  {index + 1}
                </Button>
                <span className="text-sm font-medium">{step.title}</span>
              </li>
              {index < array.length - 1 && (
                <Separator
                  className={`flex-1 ${
                    index < currentIndex ? "bg-primary" : "bg-muted"
                  }`}
                />
              )}
            </React.Fragment>
          ))}
        </ol>
      </nav>
      {/* form content */}
      <div className="space-y-4">
        {stepper.switch({
          agentType: () => <AgentTypeComponent stepper={stepper} />,
          agentForm: () => (
            <AgentFormComponent
              stepper={stepper}
              form={form}
              isPending={createAgentMutation.isPending}
              onSubmit={handleSubmit}
            />
          ),
          complete: () => (
            <CompleteComponent agentId={agentId} agentName={agentName} />
          ),
        })}
      </div>
    </CardBackground>
  );
}

const AgentTypeComponent = ({
  stepper,
}: {
  stepper: Stepper<
    {
      id: string;
      title: string;
      description: string;
    }[]
  >;
}) => {
  const agentTypes = [
    {
      icon: MessageCircle,
      heading: "Chat",
      description: "Access from our website",
    },
    {
      icon: Code,
      heading: "CLI",
      description: "Access from terminal",
    },
    {
      icon: Braces,
      heading: "API",
      description: "Access with API",
    },
  ];

  return (
    <>
      <div className="grid grid-cols-3 gap-4">
        {agentTypes.map((agentType, idx) => (
          <Button
            disabled={idx !== 0}
            key={idx}
            variant={"outline"}
            className={cn(
              idx === 0 &&
                "bg-accent-foreground hover:bg-accent-foreground border-primary",
              "py-24 border-2"
            )}
          >
            <div className="flex flex-col items-center space-y-3">
              <agentType.icon className="h-9 w-9" />
              <p className="text-xl font-bold">{agentType.heading}</p>
              <p className="text-muted-foreground">{agentType.description}</p>
            </div>
          </Button>
        ))}
      </div>
      {/* form footer  */}
      <div>
        <div className="flex justify-end gap-4">
          <Button variant="outline" disabled={true}>
            Back
          </Button>
          <Button onClick={stepper.next}>Next</Button>
        </div>
      </div>
    </>
  );
};

const AgentFormComponent = ({
  stepper,
  form,
  onSubmit,
  isPending,
}: {
  stepper: Stepper<
    {
      id: string;
      title: string;
      description: string;
    }[]
  >;
  form: UseFormReturn<z.infer<typeof createAgentSchema>, any, undefined>;
  onSubmit: (values: z.infer<typeof createAgentSchema>) => void;
  isPending: boolean;
}) => {
  return (
    <AgentForm
      stepper={stepper}
      form={form}
      onSubmit={onSubmit}
      isPending={isPending}
    />
  );
};

const CompleteComponent = ({
  agentId,
  agentName,
}: {
  agentId: string;
  agentName: string;
}) => {
  return (
    <>
      <div className="flex flex-col justify-center items-center  py-4">
        <div className="h-12 w-12 flex flex-col justify-center items-center rounded-full bg-green-300 ">
          <Check className="h-6 w-6 text-green-800" />
        </div>
        <h3 className="text-lg py-4 font-bold">Agent succesfully created!</h3>
        <p className="text-muted-foreground mb-3">
          You can try to have a conversation with your agent.
        </p>
        <Link
          href={`/agents/${agentId}`}
          target="blank"
          className={buttonVariants({ variant: "outline" })}
        >
          <MessageCircle className="h-4 w-4 mr-2"/>
          Chat with {agentName}
        </Link>
      </div>
      {/* form footer  */}
      <div>
        <div className="flex justify-end gap-4">
          <Link href="/" className={buttonVariants({ variant: "default" })}>
            Back to home
          </Link>
        </div>
      </div>
    </>
  );
};
