import { useState, useRef, useEffect, useCallback } from "react";
import { Send, Square, Plus } from "lucide-react";

import { useLLM } from "../hooks/useLLM";
import { MessageBubble } from "./MessageBubble";
import { StatusBar } from "./StatusBar";

const EXAMPLE_PROMPTS = [
  {
    label: "Solve x² + x - 12 = 0",
    prompt: "Solve x^2 + x - 12 = 0",
  },
  {
    label: "Explain quantum computing",
    prompt:
      "Explain quantum computing in simple terms. What makes it different from classical computing, and what are some real-world applications?",
  },
  {
    label: "Write a Python quicksort",
    prompt:
      "Write a clean, well-commented Python implementation of the quicksort algorithm. Include an example of how to use it.",
  },
  {
    label: "Solve a logic puzzle",
    prompt: "Five people were eating apples, A finished before B, but behind C. D finished before E, but behind B. What was the finishing order?",
  },
] as const;

interface ChatInputProps {
  showDisclaimer: boolean;
  animated?: boolean;
}

function ChatInput({ showDisclaimer, animated }: ChatInputProps) {
  const { send, stop, status, isGenerating } = useLLM();
  const isReady = status.state === "ready";
  const [input, setInput] = useState("");
  const textareaRef = useRef<HTMLTextAreaElement>(null);

  const handleSubmit = useCallback(
    (e?: React.FormEvent) => {
      e?.preventDefault();
      const text = input.trim();
      if (!text || !isReady || isGenerating) return;
      setInput("");
      if (textareaRef.current) {
        textareaRef.current.style.height = "7.5rem";
      }
      send(text);
    },
    [input, isReady, isGenerating, send],
  );

  const handleKeyDown = useCallback(
    (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
      if (e.key === "Enter" && !e.shiftKey) {
        e.preventDefault();
        handleSubmit();
      }
    },
    [handleSubmit],
  );

  return (
    <div className={`w-full ${animated ? "animate-rise-in-delayed" : ""}`}>
      <form onSubmit={handleSubmit} className="mx-auto max-w-3xl">
        <div className="relative">
          <textarea
            ref={textareaRef}
            className="w-full rounded-xl border border-[#0000001f] bg-white px-4 py-3 pb-11 text-[15px] text-black placeholder-[#6d6d6d] focus:border-[#5505af] focus:outline-none focus:ring-1 focus:ring-[#5505af] disabled:opacity-50 resize-none max-h-40 shadow-sm"
            style={{ minHeight: "7.5rem", height: "7.5rem" }}
            placeholder={isReady ? "Type a message…" : "Loading model…"}
            value={input}
            onChange={(e) => {
              setInput(e.target.value);
              e.target.style.height = "7.5rem";
              e.target.style.height =
                Math.max(e.target.scrollHeight, 120) + "px";
            }}
            onKeyDown={handleKeyDown}
            disabled={!isReady}
            autoFocus
          />

          <div className="absolute bottom-2 left-2 right-2 flex items-center justify-end pb-3 px-2">
            {isGenerating ? (
              <button
                type="button"
                onClick={stop}
                className="flex items-center justify-center rounded-lg text-[#6d6d6d] hover:text-black transition-colors cursor-pointer"
                title="Stop generating"
              >
                <Square className="h-4 w-4 fill-current" />
              </button>
            ) : (
              <button
                type="submit"
                disabled={!isReady || !input.trim()}
                className="flex items-center justify-center rounded-lg text-[#6d6d6d] hover:text-black disabled:opacity-30 transition-colors cursor-pointer"
                title="Send message"
              >
                <Send className="h-4 w-4" />
              </button>
            )}
          </div>
        </div>
      </form>

      {showDisclaimer && (
        <p className="mx-auto max-w-3xl mt-1 text-center text-xs text-[#6d6d6d]">
          No chats are sent to a server. Everything runs locally in your
          browser. AI can make mistakes. Check important info.
        </p>
      )}
    </div>
  );
}

interface ChatAppProps {
  onGoHome: () => void;
}

export function ChatApp({ onGoHome }: ChatAppProps) {
  const { messages, isGenerating, send, status, clearChat } = useLLM();
  const scrollRef = useRef<HTMLElement>(null);

  const [thinkingSeconds, setThinkingSeconds] = useState(0);
  const thinkingStartRef = useRef<number | null>(null);
  const thinkingSecondsMapRef = useRef<Map<number, number>>(new Map());
  const prevIsGeneratingRef = useRef(false);
  const messagesRef = useRef(messages);
  const thinkingSecondsRef = useRef(thinkingSeconds);
  messagesRef.current = messages;
  thinkingSecondsRef.current = thinkingSeconds;

  const isReady = status.state === "ready";
  const hasMessages = messages.length > 0;
  const showNewChat = isReady && hasMessages && !isGenerating;

  useEffect(() => {
    const el = scrollRef.current;
    if (el) {
      el.scrollTo({ top: el.scrollHeight, behavior: "smooth" });
    }
  }, [messages]);

  useEffect(() => {
    if (prevIsGeneratingRef.current && !isGenerating) {
      const lastMsg = messagesRef.current.at(-1);
      if (lastMsg?.role === "assistant" && lastMsg.reasoning && thinkingSecondsRef.current > 0) {
        thinkingSecondsMapRef.current.set(lastMsg.id, thinkingSecondsRef.current);
      }
    }
    prevIsGeneratingRef.current = isGenerating;
  }, [isGenerating]);

  useEffect(() => {
    if (!isGenerating) {
      thinkingStartRef.current = null;
      return;
    }

    thinkingStartRef.current = Date.now();
    setThinkingSeconds(0);

    const interval = setInterval(() => {
      if (thinkingStartRef.current) {
        setThinkingSeconds(
          Math.round((Date.now() - thinkingStartRef.current) / 1000),
        );
      }
    }, 500);

    return () => clearInterval(interval);
  }, [isGenerating]);

  const lastAssistant = messages.at(-1);
  useEffect(() => {
    if (isGenerating && lastAssistant?.role === "assistant" && lastAssistant.content) {
      thinkingStartRef.current = null;
    }
  }, [isGenerating, lastAssistant?.role, lastAssistant?.content]);

  return (
    <div className="flex h-full flex-col brand-surface text-black">
      <header className="flex-none flex items-center justify-between border-b border-[#0000001f] px-6 py-3 h-14">
        <button
          onClick={onGoHome}
          className="cursor-pointer transition-transform duration-300 hover:scale-[1.02]"
          title="Back to home"
        >
          <img
            src="/liquid.svg"
            alt="Liquid AI"
            className="h-6 w-auto"
            draggable={false}
          />
        </button>
        <button
          onClick={clearChat}
          className={`flex items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs text-[#6d6d6d] hover:text-black hover:bg-[#f5f5f5] transition-opacity duration-300 cursor-pointer ${
            showNewChat ? "opacity-100" : "opacity-0 pointer-events-none"
          }`}
          title="New chat"
        >
          <Plus className="h-3.5 w-3.5" />
          New chat
        </button>
      </header>

      {!hasMessages ? (
        <div className="flex flex-1 flex-col items-center justify-center px-4">
          <div className="mb-8 text-center animate-rise-in">
            <p className="text-3xl font-medium text-black">
              What can I help you with?
            </p>
          </div>

          <ChatInput showDisclaimer={false} animated />

          <div className="mt-6 flex flex-wrap justify-center gap-2 max-w-3xl animate-rise-in-delayed">
            {EXAMPLE_PROMPTS.map(({ label, prompt }) => (
              <button
                key={label}
                onClick={() => send(prompt)}
                className="rounded-lg border border-[#0000001f] bg-white px-3 py-2 text-xs text-[#6d6d6d] hover:text-black hover:border-[#5505af] transition-colors cursor-pointer shadow-sm"
              >
                {label}
              </button>
            ))}
          </div>
        </div>
      ) : (
        <>
          <main
            ref={scrollRef}
            className="min-h-0 flex-1 overflow-y-auto px-4 py-6 animate-fade-in"
          >
            <div className="mx-auto flex max-w-3xl flex-col gap-4">
              {!isReady && <StatusBar />}

              {messages.map((msg, i) => {
                const isLast = i === messages.length - 1 && msg.role === "assistant";
                return (
                  <MessageBubble
                    key={msg.id}
                    msg={msg}
                    index={i}
                    isStreaming={isGenerating && isLast}
                    thinkingSeconds={isLast ? thinkingSeconds : thinkingSecondsMapRef.current.get(msg.id)}
                    isGenerating={isGenerating}
                  />
                );
              })}
            </div>
          </main>

          <footer className="flex-none px-4 py-3 animate-fade-in relative">
            {isReady && (
              <div className="absolute bottom-full left-0 right-0 flex justify-center pointer-events-none mb-[-8px]">
                <div className="pointer-events-auto">
                  <StatusBar />
                </div>
              </div>
            )}
            <ChatInput showDisclaimer animated />
          </footer>
        </>
      )}
    </div>
  );
}
