// [nexus] Personal Assistant page — full-page chat for Personal AI mode
import { useState, useEffect, useRef, useCallback } from "react";
import { Navigate, useParams, useNavigate } from "@/lib/router";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { Bot, Send, Loader2, Plus, ArrowRight } from "lucide-react";
import { useNexusMode } from "../hooks/useNexusMode";
import { useCompany } from "../context/CompanyContext";
import { useToast } from "../context/ToastContext";
import { chatApi } from "../api/chat";
import { Button } from "@/components/ui/button";
import { VoiceRecordButton } from "@/components/VoiceRecordButton";
import { TtsButton } from "@/components/TtsButton";
import { usePiperTts } from "../hooks/usePiperTts";
import type { ChatConversationListItem, ChatMessage } from "@paperclipai/shared";


// ─── Conversation list panel ─────────────────────────────────────────────────

interface ConversationListProps {
  conversations: ChatConversationListItem[];
  selectedId: string | null;
  onSelect: (id: string) => void;
  onNew: () => void;
  isCreating: boolean;
}

function ConversationList({ conversations, selectedId, onSelect, onNew, isCreating }: ConversationListProps) {
  return (
    <aside className="w-64 flex-shrink-0 border-r border-border bg-background flex flex-col h-full">
      <div className="flex items-center justify-between px-4 py-3 border-b border-border">
        <span className="text-sm font-semibold text-foreground">Conversations</span>
        <Button
          variant="ghost"
          size="icon-sm"
          onClick={onNew}
          disabled={isCreating}
          title="New conversation"
        >
          {isCreating ? <Loader2 className="h-4 w-4 animate-spin" /> : <Plus className="h-4 w-4" />}
        </Button>
      </div>
      <nav className="flex-1 overflow-y-auto py-2">
        {conversations.length === 0 && (
          <p className="px-4 py-3 text-xs text-muted-foreground">No conversations yet. Start one below.</p>
        )}
        {conversations.map((conv) => (
          <button
            key={conv.id}
            type="button"
            onClick={() => onSelect(conv.id)}
            className={[
              "w-full text-left px-4 py-2.5 text-sm transition-colors truncate",
              selectedId === conv.id
                ? "bg-accent text-accent-foreground font-medium"
                : "text-foreground hover:bg-accent/50",
            ].join(" ")}
          >
            {conv.title || "Untitled conversation"}
          </button>
        ))}
      </nav>
    </aside>
  );
}

// ─── Message bubble ───────────────────────────────────────────────────────────

function MessageBubble({ message, streamingContent }: { message: ChatMessage | null; streamingContent?: string }) {
  const isUser = message?.role === "user";
  const content = message ? message.content : (streamingContent ?? "");
  const isStreaming = !message && streamingContent !== undefined;

  return (
    <div className={["flex gap-3 py-3", isUser ? "flex-row-reverse" : "flex-row"].join(" ")}>
      {!isUser && (
        <div className="flex-shrink-0 w-7 h-7 rounded-full bg-primary/10 flex items-center justify-center">
          <Bot className="h-4 w-4 text-primary" />
        </div>
      )}
      <div
        className={[
          "max-w-[75%] rounded-lg px-3.5 py-2 text-sm leading-relaxed",
          isUser
            ? "bg-primary text-primary-foreground rounded-br-sm"
            : "bg-muted text-foreground rounded-bl-sm",
        ].join(" ")}
      >
        <p className="whitespace-pre-wrap">{content}</p>
        {isStreaming && (
          <span className="inline-block w-1 h-4 ml-0.5 bg-current animate-pulse align-middle" />
        )}
      </div>
    </div>
  );
}

// ─── Main page ────────────────────────────────────────────────────────────────

export function PersonalAssistant() {
  const { isAssistantEnabled, isLoading: modeLoading } = useNexusMode();
  const { selectedCompany } = useCompany();
  const { conversationId: routeConvId } = useParams<{ conversationId?: string }>();
  const queryClient = useQueryClient();
  const navigate = useNavigate();
  const { pushToast } = useToast();
  const { status: ttsStatus, progress: ttsProgress, prewarm, speak, stop } = usePiperTts();

  const [selectedConvId, setSelectedConvId] = useState<string | null>(routeConvId ?? null);
  const [isCreating, setIsCreating] = useState(false);
  const [inputValue, setInputValue] = useState("");
  const [streamingContent, setStreamingContent] = useState<string | null>(null);
  const [isSending, setIsSending] = useState(false);
  const [isHandingOff, setIsHandingOff] = useState(false);
  const messagesEndRef = useRef<HTMLDivElement>(null);
  const inputRef = useRef<HTMLTextAreaElement>(null);
  const abortRef = useRef<AbortController | null>(null);

  const companyId = selectedCompany?.id ?? null;

  // Fetch conversation list
  const { data: convData, isLoading: convsLoading } = useQuery({
    queryKey: ["assistant", "conversations", companyId],
    queryFn: () => chatApi.listConversations(companyId!, { limit: 50 }),
    enabled: !!companyId,
    staleTime: 30_000,
  });

  const conversations: ChatConversationListItem[] = convData?.items ?? [];

  // Auto-select first conversation if none selected
  useEffect(() => {
    if (!selectedConvId && conversations.length > 0) {
      setSelectedConvId(conversations[0]!.id);
    }
  }, [conversations, selectedConvId]);

  // Fetch messages for selected conversation
  const { data: msgData, isLoading: msgsLoading } = useQuery({
    queryKey: ["assistant", "messages", selectedConvId],
    queryFn: () => chatApi.listMessages(selectedConvId!),
    enabled: !!selectedConvId,
    staleTime: 10_000,
  });

  const messages: ChatMessage[] = msgData?.items ?? [];

  // Scroll to bottom when messages change
  useEffect(() => {
    messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
  }, [messages, streamingContent]);

  const handleNewConversation = useCallback(async () => {
    if (!companyId || isCreating) return;
    setIsCreating(true);
    try {
      const conv = await chatApi.createConversation(companyId, {
        title: "New conversation",
      });
      queryClient.invalidateQueries({ queryKey: ["assistant", "conversations", companyId] });
      setSelectedConvId(conv.id);
    } finally {
      setIsCreating(false);
    }
  }, [companyId, isCreating, queryClient]);

  const handleSend = useCallback(async () => {
    const text = inputValue.trim();
    if (!text || !selectedConvId || isSending) return;

    setInputValue("");
    setIsSending(true);
    setStreamingContent("");

    abortRef.current?.abort();
    const abort = new AbortController();
    abortRef.current = abort;

    try {
      // Optimistically add user message to cache
      queryClient.setQueryData(
        ["assistant", "messages", selectedConvId],
        (old: { items: ChatMessage[]; hasMore?: boolean } | undefined) => ({
          items: [
            ...(old?.items ?? []),
            {
              id: `tmp-${Date.now()}`,
              conversationId: selectedConvId,
              role: "user" as const,
              content: text,
              agentId: null,
              messageType: null,
              createdAt: new Date().toISOString(),
              updatedAt: null,
            } satisfies ChatMessage,
          ],
          hasMore: old?.hasMore ?? false,
        }),
      );

      await chatApi.postMessageAndStream(
        selectedConvId,
        { content: text },
        {
          onToken: (token: string) => {
            setStreamingContent((prev) => (prev ?? "") + token);
          },
          onDone: () => {
            setStreamingContent(null);
            queryClient.invalidateQueries({ queryKey: ["assistant", "messages", selectedConvId] });
            queryClient.invalidateQueries({ queryKey: ["assistant", "conversations", companyId] });
          },
          onError: () => {
            setStreamingContent(null);
            queryClient.invalidateQueries({ queryKey: ["assistant", "messages", selectedConvId] });
          },
        },
        abort.signal,
      );
    } catch {
      setStreamingContent(null);
    } finally {
      setIsSending(false);
    }
  }, [inputValue, selectedConvId, isSending, queryClient, companyId]);

  const handleHandoff = useCallback(async () => {
    if (!selectedConvId || isHandingOff) return;
    setIsHandingOff(true);
    try {
      await chatApi.assistantHandoff(selectedConvId);
      pushToast({ title: "Conversation handed off to PM", tone: "positive" });
      navigate("/dashboard");
    } catch {
      pushToast({ title: "Handoff failed", body: "Could not create project conversation.", tone: "critical" });
    } finally {
      setIsHandingOff(false);
    }
  }, [selectedConvId, isHandingOff, navigate, pushToast]);

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

  // Mode gate — wait for mode to load before redirecting
  if (!modeLoading && !isAssistantEnabled) {
    return <Navigate to="/dashboard" replace />;
  }

  if (!companyId) {
    return (
      <div className="flex items-center justify-center h-full text-sm text-muted-foreground">
        Select a workspace to use the assistant.
      </div>
    );
  }

  return (
    <div className="flex h-full min-h-0 -m-4 md:-m-6">
      {/* Conversation list */}
      <ConversationList
        conversations={conversations}
        selectedId={selectedConvId}
        onSelect={setSelectedConvId}
        onNew={handleNewConversation}
        isCreating={isCreating}
      />

      {/* Chat area */}
      <div className="flex flex-col flex-1 min-w-0 h-full">
        {/* Header */}
        <div className="flex items-center justify-between px-6 py-3 border-b border-border shrink-0">
          <div className="flex items-center gap-2">
            <Bot className="h-5 w-5 text-primary" />
            <h1 className="text-base font-semibold text-foreground">Personal Assistant</h1>
          </div>
          <Button
            variant="outline"
            size="sm"
            className="gap-2"
            onClick={handleHandoff}
            disabled={!selectedConvId || isHandingOff}
            title="Turn this conversation into a project"
          >
            {isHandingOff ? (
              <Loader2 className="h-4 w-4 animate-spin" />
            ) : (
              <ArrowRight className="h-4 w-4" />
            )}
            Turn into project
          </Button>
        </div>

        {/* Messages */}
        <div className="flex-1 overflow-y-auto px-6 py-4">
          {!selectedConvId && !convsLoading && (
            <div className="flex flex-col items-center justify-center h-full gap-3 text-center">
              <Bot className="h-10 w-10 text-muted-foreground/50" />
              <p className="text-sm text-muted-foreground max-w-xs">
                Start a conversation with your personal AI assistant. It remembers context across sessions.
              </p>
              <Button onClick={handleNewConversation} disabled={isCreating} size="sm">
                {isCreating ? <Loader2 className="h-4 w-4 animate-spin mr-2" /> : <Plus className="h-4 w-4 mr-2" />}
                New conversation
              </Button>
            </div>
          )}

          {selectedConvId && msgsLoading && (
            <div className="flex items-center justify-center h-full">
              <Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
            </div>
          )}

          {selectedConvId && !msgsLoading && messages.length === 0 && streamingContent === null && (
            <div className="flex flex-col items-center justify-center h-full gap-2 text-center">
              <p className="text-sm text-muted-foreground">Send a message to start this conversation.</p>
            </div>
          )}

          {messages.map((msg) => (
            <div key={msg.id}>
              <MessageBubble message={msg} />
              {msg.role === "assistant" && msg.content && (
                <div className="flex justify-start pl-10 -mt-1 mb-1">
                  <TtsButton
                    status={ttsStatus}
                    progress={ttsProgress}
                    onSpeak={() => speak(msg.content)}
                    onStop={stop}
                    onPrewarm={prewarm}
                  />
                </div>
              )}
            </div>
          ))}

          {streamingContent !== null && (
            <MessageBubble message={null} streamingContent={streamingContent} />
          )}

          <div ref={messagesEndRef} />
        </div>

        {/* Input bar */}
        {selectedConvId && (
          <div className="px-6 py-4 border-t border-border shrink-0">
            <div className="flex gap-3 items-end">
              <textarea
                ref={inputRef}
                value={inputValue}
                onChange={(e) => setInputValue(e.target.value)}
                onKeyDown={handleKeyDown}
                placeholder="Message your assistant… (Enter to send, Shift+Enter for newline)"
                rows={1}
                className="flex-1 resize-none rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring min-h-[40px] max-h-[160px]"
                style={{ height: "auto" }}
                onInput={(e) => {
                  const el = e.currentTarget;
                  el.style.height = "auto";
                  el.style.height = `${Math.min(el.scrollHeight, 160)}px`;
                }}
              />
              <VoiceRecordButton
                onTranscription={(text) => setInputValue((prev) => prev ? prev + " " + text : text)}
                disabled={isSending}
              />
              <Button
                onClick={handleSend}
                disabled={!inputValue.trim() || isSending}
                size="icon"
                aria-label="Send message"
              >
                {isSending ? (
                  <Loader2 className="h-4 w-4 animate-spin" />
                ) : (
                  <Send className="h-4 w-4" />
                )}
              </Button>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}
