import { ReactNode, useEffect, useRef } from "react";
import { motion } from "framer-motion";
import { cn } from "@/lib/utils";
import { useStreamContext } from "@/providers/Stream";
import { useThreads, type Mode } from "@/providers/Thread";
import { useState, FormEvent } from "react";
import { Button } from "../ui/button";
import { AssistantMessage, AssistantMessageLoading } from "./messages/ai";
import { HumanMessage } from "./messages/human";
import { ToolResponseMessage } from "./messages/tool-response";
import { ToolRequestMessage } from "./messages/tool-request";
import { ToolRequestConfirmMessage } from "./messages/tool-request-confirm";
import { DO_NOT_RENDER_ID_PREFIX } from "@/lib/ensure-tool-responses";
import { SAALogoSVG } from "../icons/saa-logo";
import { TooltipIconButton } from "./tooltip-icon-button";
import Link from "next/link";
import {
  ArrowDown,
  ArrowLeft,
  LoaderCircle,
  PanelRightOpen,
  PanelRightClose,
  SquarePen,
  XIcon,
  Plus,
} from "lucide-react";
import { useQueryState, parseAsBoolean } from "nuqs";
import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
import ThreadHistory from "./history";
import { toast } from "sonner";
import { useMediaQuery } from "@/hooks/useMediaQuery";
import { Label } from "../ui/label";
import { Switch } from "../ui/switch";
import { GitHubSVG } from "../icons/github";
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "../ui/tooltip";
import { useFileUpload } from "@/hooks/use-file-upload";
import { ContentBlocksPreview } from "./ContentBlocksPreview";
import {
  useArtifactOpen,
  ArtifactContent,
  ArtifactTitle,
  useArtifactContext,
} from "./artifact";
import { GraphVisualization } from "./GraphVisualization";

function StickyToBottomContent(props: {
  content: ReactNode;
  footer?: ReactNode;
  className?: string;
  contentClassName?: string;
}) {
  const context = useStickToBottomContext();
  return (
    <div
      ref={context.scrollRef}
      style={{ width: "100%", height: "100%" }}
      className={props.className}
    >
      <div
        ref={context.contentRef}
        className={props.contentClassName}
      >
        {props.content}
      </div>

      {props.footer}
    </div>
  );
}

function ScrollToBottom(props: { className?: string }) {
  const { isAtBottom, scrollToBottom } = useStickToBottomContext();

  if (isAtBottom) return null;
  return (
    <Button
      variant="outline"
      className={props.className}
      onClick={() => scrollToBottom()}
    >
      <ArrowDown className="h-4 w-4" />
      <span>Scroll to bottom</span>
    </Button>
  );
}

function OpenGitHubRepo() {
  return (
    <TooltipProvider>
      <Tooltip>
        <TooltipTrigger asChild>
          <a
            href="https://github.com/alibaba/spring-ai-alibaba/"
            target="_blank"
            className="flex items-center justify-center"
          >
            <GitHubSVG
              width="24"
              height="24"
            />
          </a>
        </TooltipTrigger>
        <TooltipContent side="left">
          <p>Open GitHub repo</p>
        </TooltipContent>
      </Tooltip>
    </TooltipProvider>
  );
}

function ModeSelector({
  mode,
  setMode,
  graphList,
  isGraphsLoading,
}: {
  mode: Mode;
  setMode: (m: Mode) => void;
  graphList: string[];
  isGraphsLoading: boolean;
}) {
  const canUseGraph = !isGraphsLoading && graphList.length > 0;
  return (
    <div className="flex items-center gap-2">
      <Label className="text-sm whitespace-nowrap text-muted-foreground">Agent</Label>
      <Switch
        checked={mode === "graph"}
        onCheckedChange={(checked) => setMode(checked ? "graph" : "agent")}
        disabled={!canUseGraph}
        aria-label="Switch between Agent and Graph mode"
      />
      <Label className="text-sm whitespace-nowrap text-muted-foreground">Graph</Label>
    </div>
  );
}

function AgentSelector({
  agentList,
  selectedAgent,
  setSelectedAgent,
  isAgentsLoading,
}: {
  agentList: string[];
  selectedAgent: string;
  setSelectedAgent: (agent: string) => void;
  isAgentsLoading: boolean;
}) {
  if (isAgentsLoading) {
    return (
      <span className="text-sm text-muted-foreground">Loading agents...</span>
    );
  }
  if (agentList.length === 0) {
    return (
      <span className="text-sm text-muted-foreground">No agents available</span>
    );
  }
  return (
    <div className="flex items-center gap-2">
      <Label htmlFor="agent-select" className="text-sm whitespace-nowrap">Agent</Label>
      <select
        id="agent-select"
        value={selectedAgent}
        onChange={(e) => setSelectedAgent(e.target.value)}
        className="rounded-md border border-input bg-background px-3 py-1.5 text-sm min-w-[140px] max-w-[200px]"
      >
        {agentList.map((name) => (
          <option key={name} value={name}>{name}</option>
        ))}
      </select>
    </div>
  );
}

function GraphSelector({
  graphList,
  selectedGraph,
  setSelectedGraph,
  isGraphsLoading,
}: {
  graphList: string[];
  selectedGraph: string;
  setSelectedGraph: (graph: string) => void;
  isGraphsLoading: boolean;
}) {
  if (isGraphsLoading) {
    return (
      <span className="text-sm text-muted-foreground">Loading graphs...</span>
    );
  }
  if (graphList.length === 0) {
    return (
      <span className="text-sm text-muted-foreground">No graphs available</span>
    );
  }
  return (
    <div className="flex items-center gap-2">
      <Label htmlFor="graph-select" className="text-sm whitespace-nowrap">Graph</Label>
      <select
        id="graph-select"
        value={selectedGraph}
        onChange={(e) => setSelectedGraph(e.target.value)}
        className="rounded-md border border-input bg-background px-3 py-1.5 text-sm min-w-[140px] max-w-[200px]"
      >
        {graphList.map((name) => (
          <option key={name} value={name}>{name}</option>
        ))}
      </select>
    </div>
  );
}

export function Thread() {
  const [artifactContext, setArtifactContext] = useArtifactContext();
  const [artifactOpen, closeArtifact] = useArtifactOpen();

  const [threadId, _setThreadId] = useQueryState("threadId");
  const [chatHistoryOpen, setChatHistoryOpen] = useQueryState(
    "chatHistoryOpen",
    parseAsBoolean.withDefault(false),
  );
  const [hideToolCalls, setHideToolCalls] = useQueryState(
    "hideToolCalls",
    parseAsBoolean.withDefault(false),
  );
  const [input, setInput] = useState("");
  const {
    contentBlocks,
    setContentBlocks,
    handleFileUpload,
    dropRef,
    removeBlock,
    resetBlocks: _resetBlocks,
    dragOver,
    handlePaste,
  } = useFileUpload();
  const [firstTokenReceived, setFirstTokenReceived] = useState(false);
  const isLargeScreen = useMediaQuery("(min-width: 1024px)");

  const stream = useStreamContext();
  const messages = stream.messages;
  const isLoading = stream.isStreaming;

  // Import thread context to synchronize with query state
  const {
    setCurrentThreadId,
    agentList,
    selectedAgent,
    setSelectedAgent,
    isAgentsLoading,
    mode,
    setMode,
    graphList,
    selectedGraph,
    setSelectedGraph,
    isGraphsLoading,
    isLocked,
  } = useThreads();

  // Sync threadId query state with ThreadProvider's currentThreadId
  // This handles cases where threadId changes from outside (e.g., from history)
  useEffect(() => {
    setCurrentThreadId(threadId);
  }, [threadId, setCurrentThreadId]);

  // Debug: Log messages whenever they change
  useEffect(() => {
    console.log('[Thread] Messages updated:', messages.length, messages);
    messages.forEach((msg, idx) => {
      console.log(`[Thread] Message ${idx}:`, {
        id: msg.id,
        type: msg.message.messageType,
        content: msg.message.content?.substring(0, 50),
        fullMessage: msg
      });
    });
  }, [messages]);

  const lastError = useRef<string | undefined>(undefined);

  const setThreadId = (id: string | null) => {
    _setThreadId(id);

    // Synchronize with ThreadProvider's currentThreadId
    // This will trigger the useEffect in StreamProvider to clear messages
    setCurrentThreadId(id);

    // close artifact and reset artifact context
    closeArtifact();
    setArtifactContext({});
  };

  // TODO: this should be part of the useStream hook
  const prevMessageLength = useRef(0);
  useEffect(() => {
    if (
      messages.length !== prevMessageLength.current &&
      messages?.length &&
      messages[messages.length - 1].message.messageType === "assistant"
    ) {
      setFirstTokenReceived(true);
    }

    prevMessageLength.current = messages.length;
  }, [messages]);

  const handleSubmit = async (e: FormEvent) => {
    e.preventDefault();
    if ((input.trim().length === 0 && contentBlocks.length === 0) || isLoading)
      return;
    setFirstTokenReceived(false);

    // Extract text content from input and content blocks
    let messageContent = input.trim();

    // For now, we'll concatenate text from content blocks
    // TODO: Handle multimodal content properly when backend supports it
    if (contentBlocks.length > 0) {
      const textBlocks = contentBlocks
        .filter((block: any) => block.type === "text")
        .map((block: any) => block.text)
        .join("\n");
      messageContent = messageContent ? `${messageContent}\n${textBlocks}` : textBlocks;
    }

    if (!messageContent) return;

    // Send message using Spring AI API
    await stream.sendMessage(messageContent);

    setInput("");
    setContentBlocks([]);
  };

  const chatStarted = !!threadId || !!messages.length;

  // Check if current thread has a placeholder message (indicates message history loading not supported)
  const hasPlaceholderMessage = messages.length === 1 &&
    messages[0].message.metadata?.isPlaceholder === true;

  return (
    <div className="flex h-screen w-full overflow-hidden">
      <div className="relative hidden lg:flex">
        <motion.div
          className="absolute z-20 h-full overflow-hidden border-r bg-white"
          style={{ width: 300 }}
          animate={
            isLargeScreen
              ? { x: chatHistoryOpen ? 0 : -300 }
              : { x: chatHistoryOpen ? 0 : -300 }
          }
          initial={{ x: -300 }}
          transition={
            isLargeScreen
              ? { type: "spring", stiffness: 300, damping: 30 }
              : { duration: 0 }
          }
        >
          <div
            className="relative h-full"
            style={{ width: 300 }}
          >
            <ThreadHistory />
          </div>
        </motion.div>
      </div>

      <div
        className={cn(
          "grid w-full grid-cols-[1fr_0fr] transition-all duration-500",
          artifactOpen && "grid-cols-[3fr_2fr]",
        )}
      >
        <motion.div
          className={cn(
            "relative flex min-w-0 flex-1 flex-col overflow-hidden",
            !chatStarted && "grid-rows-[1fr]",
          )}
          layout={isLargeScreen}
          animate={{
            marginLeft: chatHistoryOpen ? (isLargeScreen ? 300 : 0) : 0,
            width: chatHistoryOpen
              ? isLargeScreen
                ? "calc(100% - 300px)"
                : "100%"
              : "100%",
          }}
          transition={
            isLargeScreen
              ? { type: "spring", stiffness: 300, damping: 30 }
              : { duration: 0 }
          }
        >
          {!chatStarted && mode === "graph" && selectedGraph && !isLocked && (
            <div className="absolute top-14 left-4 right-4 z-0">
              <GraphVisualization graphName={selectedGraph} className="max-h-48" />
            </div>
          )}
          {!chatStarted && (
            <div className="absolute top-0 left-0 z-10 flex w-full items-center justify-between gap-3 p-2 pl-4">
              <div>
                {(!chatHistoryOpen || !isLargeScreen) && (
                  <Button
                    className="hover:bg-gray-100"
                    variant="ghost"
                    onClick={() => setChatHistoryOpen((p) => !p)}
                  >
                    {chatHistoryOpen ? (
                      <PanelRightOpen className="size-5" />
                    ) : (
                      <PanelRightClose className="size-5" />
                    )}
                  </Button>
                )}
              </div>
              <div className="absolute top-2 right-4 flex items-center gap-3">
                {isLocked ? (
                  <Link href="/index.html">
                    <Button variant="ghost" size="sm">
                      <ArrowLeft className="mr-2 h-4 w-4" />
                      Back
                    </Button>
                  </Link>
                ) : (
                  <>
                    <ModeSelector
                      mode={mode}
                      setMode={setMode}
                      graphList={graphList}
                      isGraphsLoading={isGraphsLoading}
                    />
                    {mode === "agent" && (
                      <AgentSelector
                        agentList={agentList}
                        selectedAgent={selectedAgent}
                        setSelectedAgent={setSelectedAgent}
                        isAgentsLoading={isAgentsLoading}
                      />
                    )}
                    {mode === "graph" && (
                      <GraphSelector
                        graphList={graphList}
                        selectedGraph={selectedGraph}
                        setSelectedGraph={setSelectedGraph}
                        isGraphsLoading={isGraphsLoading}
                      />
                    )}
                  </>
                )}
                <OpenGitHubRepo />
              </div>
            </div>
          )}
          {chatStarted && (
            <div className="relative z-10 flex items-center justify-between gap-3 p-2">
              <div className="relative flex items-center justify-start gap-2">
                <div className="absolute left-0 z-10">
                  {(!chatHistoryOpen || !isLargeScreen) && (
                    <Button
                      className="hover:bg-gray-100"
                      variant="ghost"
                      onClick={() => setChatHistoryOpen((p) => !p)}
                    >
                      {chatHistoryOpen ? (
                        <PanelRightOpen className="size-5" />
                      ) : (
                        <PanelRightClose className="size-5" />
                      )}
                    </Button>
                  )}
                </div>
                {isLocked ? (
                  <Link href="/index.html" className="flex items-center gap-2">
                    <ArrowLeft className="h-5 w-5 text-muted-foreground" />
                    <span className="text-xl font-semibold tracking-tight">
                      <span className="text-green-600">Spring AI Alibaba</span> · {selectedAgent}
                    </span>
                  </Link>
                ) : (
                  <motion.button
                    className="flex cursor-pointer items-center gap-2"
                    onClick={() => setThreadId(null)}
                    animate={{
                      marginLeft: !chatHistoryOpen ? 48 : 0,
                    }}
                    transition={{
                      type: "spring",
                      stiffness: 300,
                      damping: 30,
                    }}
                  >
                    <span className="text-xl font-semibold tracking-tight">
                      <span className="text-green-600">Spring AI Alibaba</span> Agent Chat
                    </span>
                  </motion.button>
                )}
              </div>

              <div className="flex items-center gap-4">
                {isLocked ? (
                  <Link href="/index.html">
                    <Button variant="ghost" size="sm">
                      <ArrowLeft className="mr-2 h-4 w-4" />
                      Back
                    </Button>
                  </Link>
                ) : (
                  <>
                    <ModeSelector
                      mode={mode}
                      setMode={setMode}
                      graphList={graphList}
                      isGraphsLoading={isGraphsLoading}
                    />
                    {mode === "agent" && (
                      <AgentSelector
                        agentList={agentList}
                        selectedAgent={selectedAgent}
                        setSelectedAgent={setSelectedAgent}
                        isAgentsLoading={isAgentsLoading}
                      />
                    )}
                    {mode === "graph" && (
                      <GraphSelector
                        graphList={graphList}
                        selectedGraph={selectedGraph}
                        setSelectedGraph={setSelectedGraph}
                        isGraphsLoading={isGraphsLoading}
                      />
                    )}
                  </>
                )}
                <div className="flex items-center">
                  <OpenGitHubRepo />
                </div>
                <TooltipIconButton
                  size="lg"
                  className="p-4"
                  tooltip={isLocked ? "New thread" : "New thread"}
                  variant="ghost"
                  onClick={() => {
                    setThreadId(null);
                  }}
                >
                    <Plus className="size-5" />
                  </TooltipIconButton>
              </div>

              <div className="from-background to-background/0 absolute inset-x-0 top-full h-5 bg-gradient-to-b" />
            </div>
          )}

          <StickToBottom className="relative flex-1 overflow-hidden">
            <StickyToBottomContent
              className={cn(
                "absolute inset-0 overflow-y-scroll px-4 [&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-gray-300 [&::-webkit-scrollbar-track]:bg-transparent",
                !chatStarted && "mt-[25vh] flex flex-col items-stretch",
                chatStarted && "grid grid-rows-[1fr_auto]",
              )}
              contentClassName="pt-8 pb-16  max-w-3xl mx-auto flex flex-col gap-4 w-full"
              content={
                <>
                  {(() => {
                    const filteredMessages = messages.filter((m) => !m.id?.startsWith(DO_NOT_RENDER_ID_PREFIX));
                    console.log('[Thread] Rendering messages:', {
                      total: messages.length,
                      filtered: filteredMessages.length,
                      messages: filteredMessages.map(m => ({
                        id: m.id,
                        type: m.message.messageType
                      }))
                    });
                    return filteredMessages.map((message, index) => {
                      console.log('[Thread] Rendering message:', message.message.messageType, message);

                      const messageType = message.message.messageType;
                      const key = message.id || `${messageType}-${index}`;

                      // Hide tool-related messages if hideToolCalls is enabled
                      if (hideToolCalls && (
                        messageType === "tool-request" ||
                        messageType === "tool-confirm" ||
                        messageType === "tool"
                      )) {
                        console.log('[Thread] Hiding tool message due to hideToolCalls:', messageType);
                        return null;
                      }

                      switch (messageType) {
                        case "user":
                          return <HumanMessage key={key} message={message} />;

                        case "assistant":
                          return <AssistantMessage key={key} message={message} />;

                        case "tool-request":
                          return <ToolRequestMessage key={key} message={message} />;

                        case "tool-confirm":
                          return <ToolRequestConfirmMessage key={key} message={message} />;

                        case "tool":
                          return <ToolResponseMessage key={key} message={message} />;

                        default:
                          console.log('[Thread] Unknown message type:', messageType);
                          return null;
                      }
                    });
                  })()}
                  {isLoading && !firstTokenReceived && (
                    <AssistantMessageLoading />
                  )}
                </>
              }
              footer={
                <div className="sticky bottom-0 flex flex-col items-center gap-8 bg-white">
                  {!chatStarted && (
                    <div className="flex items-center gap-3">
                      {/*<SAALogoSVG className="h-8 flex-shrink-0" />*/}
                      <h1 className="text-2xl font-semibold tracking-tight">
                        <span className="text-green-600 italic">Spring AI Alibaba</span> Agent Chat
                      </h1>
                    </div>
                  )}

                  <ScrollToBottom className="animate-in fade-in-0 zoom-in-95 absolute bottom-full left-1/2 mb-4 -translate-x-1/2" />

                  <div
                    ref={dropRef}
                    className={cn(
                      "bg-muted relative z-10 mx-auto mb-8 w-full max-w-3xl rounded-2xl shadow-xs transition-all",
                      dragOver
                        ? "border-primary border-2 border-dotted"
                        : "border border-solid",
                    )}
                  >
                    <form
                      onSubmit={handleSubmit}
                      className="mx-auto grid max-w-3xl grid-rows-[1fr_auto] gap-2"
                    >
                      <ContentBlocksPreview
                        blocks={contentBlocks}
                        onRemove={removeBlock}
                      />
                      <textarea
                        value={input}
                        onChange={(e) => setInput(e.target.value)}
                        onPaste={handlePaste}
                        onKeyDown={(e) => {
                          if (
                            e.key === "Enter" &&
                            !e.shiftKey &&
                            !e.metaKey &&
                            !e.nativeEvent.isComposing
                          ) {
                            e.preventDefault();
                            const el = e.target as HTMLElement | undefined;
                            const form = el?.closest("form");
                            form?.requestSubmit();
                          }
                        }}
                        placeholder={hasPlaceholderMessage ? "Please create a new thread to start chatting..." : "Type your message..."}
                        disabled={hasPlaceholderMessage}
                        className={cn(
                          "field-sizing-content resize-none border-none bg-transparent p-3.5 pb-0 shadow-none ring-0 outline-none focus:ring-0 focus:outline-none",
                          hasPlaceholderMessage && "opacity-50 cursor-not-allowed"
                        )}
                      />

                      <div className="flex items-center gap-6 p-2 pt-4">
                        <div>
                          <div className="flex items-center space-x-2">
                            <Switch
                              id="render-tool-calls"
                              checked={hideToolCalls ?? false}
                              onCheckedChange={setHideToolCalls}
                            />
                            <Label
                              htmlFor="render-tool-calls"
                              className="text-sm text-gray-600"
                            >
                              Hide Tool Calls
                            </Label>
                          </div>
                        </div>
                        <div className="flex items-center gap-2 opacity-50 cursor-not-allowed">
                          <Plus className="size-5 text-gray-400" />
                          <span className="text-sm text-gray-400">
                            Upload PDF or Image
                          </span>
                          <span className="text-xs text-gray-400 italic">
                            (Coming Soon)
                          </span>
                        </div>
                        {/* Temporarily disabled file upload feature */}
                        {/* <input
                          id="file-input"
                          type="file"
                          onChange={handleFileUpload}
                          multiple
                          accept="image/jpeg,image/png,image/gif,image/webp,application/pdf"
                          className="hidden"
                        /> */}
                        <Button
                          type="submit"
                          className="ml-auto shadow-md transition-all"
                          disabled={
                            isLoading ||
                            (!input.trim() && contentBlocks.length === 0)
                          }
                        >
                          Send
                        </Button>
                      </div>
                    </form>
                  </div>
                </div>
              }
            />
          </StickToBottom>
        </motion.div>
        <div className="relative flex flex-col border-l">
          <div className="absolute inset-0 flex min-w-[30vw] flex-col">
            <div className="grid grid-cols-[1fr_auto] border-b p-4">
              <ArtifactTitle className="truncate overflow-hidden" />
              <button
                onClick={closeArtifact}
                className="cursor-pointer"
              >
                <XIcon className="size-5" />
              </button>
            </div>
            <ArtifactContent className="relative flex-grow" />
          </div>
        </div>
      </div>
    </div>
  );
}
