import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Separator } from "@/components/ui/separator";
import { getConversationHistory } from "@/services/get-conversation-history";
import { createFileRoute, notFound } from "@tanstack/react-router";
import { LoaderCircleIcon, SendHorizontalIcon } from "lucide-react";
import React, { useEffect, useRef, useState } from "react";
import { streamingFetch } from "@/utils/streaming-fetch";
import { env } from "@/env";
import ConversationBubble from "@/components/conversation-bubble";

interface ConversationData {
  key: React.Key;
  content: string;
  type: "question" | "response";
}

export const Route = createFileRoute("/conversation/$sessionId")({
  component: RouteComponent,
  loader: async ({ params }) => {
    const data = await getConversationHistory(params.sessionId);
    if (!data) {
      throw notFound();
    }
    return data;
  },
});

function RouteComponent() {
  const { history, title } = Route.useLoaderData();
  const { sessionId } = Route.useParams();
  const [inputValue, setInputValue] = useState("");
  const [isBusy, setIsBusy] = useState(false);
  const [conversationPieces, setConversationPieces] = useState<
    ConversationData[]
  >([]);
  const scrollContainer = useRef<HTMLDivElement>(null);

  const scrollToBottom = () => {
    setTimeout(() => {
      if (scrollContainer.current) {
        scrollContainer.current.scrollTo({
          top: scrollContainer.current.scrollHeight,
          behavior: "smooth",
        });
      }
    }, 100);
  };

  // Auto-scroll when conversation pieces change
  useEffect(() => {
    scrollToBottom();
  }, [conversationPieces]);

  const handleSendQuestion = async () => {
    if (!inputValue || isBusy) {
      return;
    }
    const question = inputValue.trim();
    setIsBusy(true);
    setInputValue("");

    setConversationPieces((state) => [
      ...state,
      {
        key: new Date().getTime(),
        content: question,
        type: "question",
      },
    ]);

    try {
      setConversationPieces((state) => [
        ...state,
        {
          key: new Date().getTime(),
          content: "",
          type: "response",
        },
      ]);
      scrollToBottom();

      let idx = 0;
      for await (const chunk of streamingFetch(() =>
        fetch(`${env.VITE_API_URL}/ask-conversation`, {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({ question, session_id: sessionId }),
        })
      )) {
        setConversationPieces((state) => {
          const stateCopy = [...state];
          const lastItem = stateCopy.pop()!;
          return [
            ...stateCopy,
            {
              key: new Date().getTime(),
              content: idx++ === 0 ? chunk : lastItem.content + chunk,
              type: "response",
            },
          ];
        });
        scrollToBottom();
      }
    } catch (err) {
      console.error("There was an error receiving chunks", err);
    } finally {
      setIsBusy(false);
    }
  };

  return (
    <div className="flex justify-center p-3 h-screen">
      <div className="flex flex-col w-4xl gap-3 h-full max-h-full">
        <Card
          className="flex flex-col min-h-0 overflow-hidden"
          style={{ height: "calc(100vh - 160px)" }}
        >
          <CardHeader className="flex-shrink-0">
            <CardTitle>{title}</CardTitle>
            <Separator orientation="horizontal" />
          </CardHeader>
          <CardContent className="flex-1 min-h-0 p-4 overflow-hidden">
            <div
              ref={scrollContainer}
              className="flex flex-col gap-2 rounded-sm bg-neutral-50 h-full border border-neutral-200 shadow-2xs overflow-y-auto p-2"
            >
              {history.map((h, idx) => (
                <React.Fragment key={idx}>
                  <ConversationBubble
                    type="question"
                    active={false}
                    content={h.question}
                  />
                  <ConversationBubble
                    type="response"
                    active={false}
                    content={h.answer}
                  />
                </React.Fragment>
              ))}
              {!!history.length && (
                <div className="flex flex-col items-center">
                  <Separator orientation="horizontal" />
                  <span className="text-xs text-neutral-400">
                    End of history
                  </span>
                </div>
              )}
              {!!conversationPieces.length && (
                <>
                  {conversationPieces.map((c) => (
                    <ConversationBubble
                      key={c.key}
                      type={c.type}
                      content={c.content}
                    />
                  ))}
                </>
              )}
            </div>
          </CardContent>
        </Card>
        <div className="flex gap-3 flex-shrink-0">
          <Input
            className="flex-1"
            placeholder="Start typing..."
            value={inputValue}
            onChange={(e) => setInputValue(e.target.value)}
            disabled={isBusy}
          />
          <Button size="icon" disabled={isBusy} onClick={handleSendQuestion}>
            {isBusy ? (
              <LoaderCircleIcon className="animate-spin" />
            ) : (
              <SendHorizontalIcon />
            )}
          </Button>
        </div>
      </div>
    </div>
  );
}
