"use client";

import CodeViewer from "@/components/code-viewer";
import { useScrollTo } from "@/hooks/use-scroll-to";
import { CheckIcon } from "@heroicons/react/16/solid";
import { ArrowLongRightIcon, ChevronDownIcon } from "@heroicons/react/20/solid";
import { AnimatePresence, motion } from "framer-motion";
import { FormEvent, useEffect, useState } from "react";
import LoadingDots from "../../components/loading-dots";
import * as Select from "@radix-ui/react-select";

function removeCodeFormatting(code: string): string {
  return code.replace(/```(?:typescript|javascript|tsx)?\n([\s\S]*?)```/g, "$1").trim();
}

export default function Home() {
  const [status, setStatus] = useState<"initial" | "creating" | "created">("initial");
  const [prompt, setPrompt] = useState("");
  const [model, setModel] = useState("gemini-2.0-flash-exp");
  const [generatedCode, setGeneratedCode] = useState("");
  const [ref, scrollTo] = useScrollTo();

  const models = [
    { label: "gemini-2.0-flash-exp", value: "gemini-2.0-flash-exp" },
    { label: "gemini-1.5-pro", value: "gemini-1.5-pro" },
    { label: "gemini-1.5-flash", value: "gemini-1.5-flash" },
  ];

  const loading = status === "creating";

  async function createApp(e: FormEvent<HTMLFormElement>) {
    e.preventDefault();
    setStatus("creating");
    setGeneratedCode("");

    try {
      const res = await fetch("/api/generateCode", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          model,
          messages: [{ role: "user", content: prompt }],
        }),
      });

      if (!res.ok) {
        const errorBody = await res.text();
        throw new Error(`HTTP Error ${res.status}: ${res.statusText}. ${errorBody}`);
      }

      const reader = res.body?.getReader();
      if (!reader) throw new Error("The response does not contain a body.");

      let receivedData = "";
      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        receivedData += new TextDecoder().decode(value);
      }

      const cleanedData = removeCodeFormatting(receivedData);
      setGeneratedCode(cleanedData);
      setStatus("created");
    } catch (error: any) {
      console.error("Error during code generation:", error.message);
      setStatus("initial");
    }
  }

  useEffect(() => {
    const el = document.querySelector(".cm-scroller");
    if (el && loading) {
      const end = el.scrollHeight - el.clientHeight;
      el.scrollTo({ top: end });
    }
  }, [loading, generatedCode]);

  return (
    <main className="mt-12 flex w-full flex-1 flex-col items-center px-4 text-center sm:mt-1">
      <a
        className="mb-4 inline-flex h-7 items-center rounded-3xl bg-gray-300/50 px-7 py-5 shadow-sm dark:bg-gray-800/50"
        href="https://ai.google.dev/gemini-api/docs"
        target="_blank"
      >
        Powered by <span className="font-medium">Gemini API</span>
      </a>
      <h1 className="my-6 max-w-3xl text-4xl font-bold text-gray-800 sm:text-6xl">
        Turn your <span className="text-blue-600">idea</span>
        <br /> into an <span className="text-blue-600">app</span>
      </h1>

      <form className="w-full max-w-xl" onSubmit={createApp}>
        <fieldset disabled={loading} className="disabled:opacity-75">
          <div className="relative mt-5">
            <div className="relative flex bg-white shadow-md rounded-xl">
              <textarea
                rows={3}
                required
                value={prompt}
                onChange={(e) => setPrompt(e.target.value)}
                className="w-full resize-none rounded-l-xl p-4"
                placeholder="Build me a calculator app..."
              />
              <button
                type="submit"
                disabled={loading}
                className="bg-blue-500 text-white px-5 rounded-r-xl"
              >
                {status === "creating" ? <LoadingDots /> : <ArrowLongRightIcon />}
              </button>
            </div>
          </div>

          <div className="mt-6 flex items-center gap-4">
            <label className="text-gray-500">Model:</label>
            <Select.Root value={model} onValueChange={(value) => setModel(value)}>
              <Select.Trigger className="p-2 bg-gray-100 rounded-md">{model}</Select.Trigger>
              <Select.Content>
                {models.map((model) => (
                  <Select.Item key={model.value} value={model.value}>
                    {model.label}
                  </Select.Item>
                ))}
              </Select.Content>
            </Select.Root>
          </div>
        </fieldset>
      </form>

      {status !== "initial" && (
        <motion.div initial={{ height: 0 }} animate={{ height: "auto" }} className="w-full">
          <CodeViewer code={generatedCode} />
        </motion.div>
      )}
    </main>
  );
}
