import { Ban, Send } from "lucide-react";
import { useEffect, useMemo, useRef, useState } from "react";

import { Button } from "@/components/ui/button";
import { ScrollArea } from "@/components/ui/scroll-area";
import { MessageBubble } from "./MessageBubble";
import { ThinkingIndicator } from "./ThinkingIndicator";

import {
  useAcpCancel,
  useAcpHistory,
  useAcpPrompt,
  useAcpStatus,
} from "@/lib/api/acp";
import { cn } from "@/lib/utils";

interface AcpPanelProps {
  workspaceId: string | null;
}

interface LocalError {
  id: number;
  message: string;
}

function StatusPill({ status }: { status: ReturnType<typeof useAcpStatus> }) {
  let dotClass = "bg-muted-foreground";
  let label = "not started";

  if (status.isPending) {
    dotClass = "bg-muted-foreground animate-pulse";
    label = "initializing…";
  } else if (status.isError) {
    dotClass = "bg-destructive";
    label = "error";
  } else if (status.data) {
    if (status.data.error) {
      dotClass = "bg-destructive";
      label = `error: ${status.data.error}`;
    } else if (status.data.ready) {
      dotClass = "bg-green-500";
      label = "ready";
    } else if (status.data.running) {
      dotClass = "bg-muted-foreground animate-pulse";
      label = "initializing…";
    } else {
      dotClass = "bg-muted-foreground";
      label = "not started";
    }
  }

  return (
    <div className="flex items-center gap-1.5">
      <span className={cn("h-2 w-2 shrink-0 rounded-full", dotClass)} />
      <span
        className={cn(
          "max-w-40 truncate",
          status.isError || status.data?.error
            ? "text-destructive"
            : "text-muted-foreground",
        )}
        title={label}
      >
        {label}
      </span>
    </div>
  );
}

export function AcpPanel({ workspaceId }: AcpPanelProps) {
  const acpStatus = useAcpStatus(workspaceId);
  const acpHistory = useAcpHistory(workspaceId);
  const prompt = useAcpPrompt();
  const cancel = useAcpCancel();

  const [input, setInput] = useState("");
  const [localErrors, setLocalErrors] = useState<LocalError[]>([]);
  const scrollRootRef = useRef<HTMLDivElement | null>(null);
  const sentinelRef = useRef<HTMLDivElement | null>(null);

  const messages = useMemo(
    () => acpHistory.data?.messages ?? [],
    [acpHistory.data],
  );

  useEffect(() => {
    if (prompt.error) {
      const id = Date.now();
      setLocalErrors((prev) => [
        ...prev,
        { id, message: prompt.error?.message ?? "Failed to send prompt" },
      ]);
      const timeout = window.setTimeout(() => {
        setLocalErrors((prev) => prev.filter((e) => e.id !== id));
      }, 5000);
      return () => window.clearTimeout(timeout);
    }
  }, [prompt.error]);

  useEffect(() => {
    const root = scrollRootRef.current;
    const sentinel = sentinelRef.current;
    if (!root || !sentinel) return;

    const viewport = root.querySelector(
      "[data-radix-scroll-area-viewport]",
    ) as HTMLDivElement | null;
    if (!viewport) return;

    const distanceFromBottom =
      viewport.scrollHeight - viewport.scrollTop - viewport.clientHeight;
    if (distanceFromBottom <= 80) {
      sentinel.scrollIntoView({ behavior: "smooth", block: "end" });
    }
  }, [messages, prompt.isPending]);

  const handleSend = () => {
    const content = input.trim();
    if (!content || !workspaceId || prompt.isPending) return;
    prompt.mutate({ workspaceId, content });
    setInput("");
  };

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

  const isReady = acpStatus.data?.ready === true;
  const sessionId = acpStatus.data?.sessionId;
  const trimmedSession =
    sessionId && sessionId.length > 12
      ? `${sessionId.slice(0, 12)}…`
      : sessionId;

  if (!workspaceId) {
    return (
      <section className="flex h-full w-full items-center justify-center bg-background text-sm text-muted-foreground">
        Select a workspace to use the agent.
      </section>
    );
  }

  return (
    <section className="flex h-full w-full flex-col overflow-hidden bg-background">
      <header className="flex h-8 shrink-0 items-center justify-between border-b border-border bg-sidebar px-3 text-xs">
        <div className="flex items-center gap-2">
          <span className="font-medium text-foreground">Agent</span>
          {sessionId && (
            <span
              className="font-mono text-[10px] text-muted-foreground"
              title={sessionId}
            >
              sess:{trimmedSession}
            </span>
          )}
        </div>
        <StatusPill status={acpStatus} />
      </header>

      <ScrollArea ref={scrollRootRef} className="flex-1">
        <div className="flex flex-col gap-3 p-3">
          {messages.length === 0 && isReady && (
            <div className="flex flex-1 items-center justify-center py-8 text-sm text-muted-foreground">
              Send a message to start the conversation.
            </div>
          )}
          {messages.map((message, index) => (
            <MessageBubble key={index} message={message} />
          ))}
          {prompt.isPending && <ThinkingIndicator />}
          {localErrors.map((err) => (
            <div
              key={err.id}
              className="text-center text-xs text-destructive"
            >
              {err.message}
            </div>
          ))}
          <div ref={sentinelRef} />
        </div>
      </ScrollArea>

      <div className="flex h-12 shrink-0 items-center gap-2 border-t border-border bg-background px-3">
        <textarea
          value={input}
          onChange={(e) => setInput(e.target.value)}
          onKeyDown={handleKeyDown}
          placeholder="Ask the agent…"
          rows={1}
          maxLength={4000}
          disabled={!workspaceId}
          className="max-h-32 min-h-8 flex-1 resize-none rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
        />
        {prompt.isPending ? (
          <Button
            variant="outline"
            size="sm"
            onClick={() => workspaceId && cancel.mutate(workspaceId)}
            disabled={cancel.isPending}
          >
            <Ban className="size-4" aria-hidden="true" />
            <span className="sr-only">Cancel</span>
          </Button>
        ) : (
          <Button
            size="sm"
            onClick={handleSend}
            disabled={!input.trim() || prompt.isPending}
          >
            <Send className="size-4" aria-hidden="true" />
            <span className="sr-only">Send</span>
          </Button>
        )}
      </div>
    </section>
  );
}
