import * as React from "react";
import ReactMarkdown from "react-markdown";
import rehypeRaw from "rehype-raw";
import rehypeSanitize, { defaultSchema } from "rehype-sanitize";
import { Bot, ChevronLeft, ChevronRight, SquarePen, X } from "lucide-react";
import { cn } from "@/lib/utils";
import { Sheet, SheetContent } from "@/components/ui/sheet";
import { Button } from "@/components/ui/button";
import { ChatInputArea } from "@/components/ui/chat-input-area";
import { Spinner } from "@/components/ui/spinner";
import {
  SupportContextChip,
  SupportSuggestedQuestion,
  SupportStepGuideCard,
  SupportArticleCard,
} from "./support-agent-primitives";
import type {
  SupportAgentContext,
  SupportAgentRichContent,
} from "./support-agent-primitives";

/**
 * SupportAgentPanel — WealthX DS (Organism)
 *
 * Right-side slide-over panel providing system guidance to backoffice users.
 * Answers questions about how to use WealthX, optionally grounded in the
 * current page and entity context (Rovo pattern).
 *
 * Follows Jira Rovo's sidebar chat pattern exactly:
 *   — Non-blocking: no overlay, main UI remains interactive behind the panel
 *   — Two header modes: home (bot icon) vs chat (back arrow + conversation title)
 *   — Context chip: optional page+entity label below header (Rovo: context awareness)
 *   — Home state: New Chat CTA button + Recents list + Suggested questions
 *   — Chat state: message thread with optional rich content cards
 *   — Rich messages: AI responses can embed StepGuideCard or ArticleCard
 *
 * Pure display component — all state and API calls are managed by the consumer.
 * Only local state: textarea value (input) and textarea height (auto-resize).
 *
 * Layout — Home state:
 *   Header  — [Bot icon]  Support Assistant                    [✕]
 *   Content — [✏ New chat]
 *             RECENTS
 *             > Previous conversation title
 *             View all →
 *             SUGGESTED
 *             > Suggested question card
 *   Footer  — textarea + send
 *
 * Layout — Chat state:
 *   Header  — [←]  Conversation title                         [✕]
 *   Content — chat thread (bubbles + optional rich cards)
 *   Footer  — textarea + send
 */

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

export interface SupportAgentMessage {
  id: string;
  role: "user" | "assistant";
  /** Plain text content always shown. */
  content: string;
  /**
   * Optional rich content rendered below the text bubble.
   * Supported: step-guide | article
   */
  richContent?: SupportAgentRichContent;
  /** True while the assistant response is streaming in. */
  isStreaming?: boolean;
  /**
   * Status text shown beside the animated dots while the response streams
   * (e.g. "Checking the help center"). Rendered only while the bubble is empty
   * and streaming. The trailing "…" animates on its own — do not include dots here.
   */
  streamingLabel?: string;
  /** True if the message errored. */
  isErrored?: boolean;
}

/** A recent conversation entry shown in the home-state Recents list. */
export interface SupportAgentRecentConversation {
  id: string;
  /** Short title (first user message or AI-generated summary). */
  title: string;
}

export interface SupportAgentPanelProps {
  open: boolean;
  onClose: () => void;
  /** Chat message history. Empty array = show home state. */
  messages?: SupportAgentMessage[];
  /**
   * Recent conversations shown in the home state Recents list (Rovo pattern).
   * Clicking an entry fires onOpenConversation(id).
   */
  recentConversations?: SupportAgentRecentConversation[];
  /**
   * Pre-set help questions shown in the home state (Rovo: conversation starters).
   * Shown below Recents when provided.
   */
  suggestedQuestions?: string[];
  /**
   * Title shown in the chat-mode header (replaces bot icon row).
   * Typically the first user message or an AI-generated session title.
   * Required for the back-arrow chat header to appear.
   */
  conversationTitle?: string;
  /**
   * Current backoffice page context — page name and optional entity being viewed.
   * When provided, renders a SupportContextChip below the panel header so the
   * AI can ground responses to the user's current location (Rovo pattern).
   *
   * Example: { pageLabel: "Loan Applications", entityLabel: "John Smith — #4521" }
   */
  context?: SupportAgentContext;
  /** True while the assistant is generating a response. */
  isStreaming?: boolean;
  /** True while initial data is loading — shows full-panel spinner. */
  isLoading?: boolean;
  /** Called when the user submits a message. Input is cleared after firing. */
  onSendMessage?: (text: string) => void;
  /** Called when the user selects files via the attachment button. */
  onAttachFile?: (files: FileList) => void;
  /** Called when the user selects images via the image upload button. */
  onAttachImage?: (files: FileList) => void;
  /** Called when the user clicks "New chat" — resets to home state. */
  onNewChat?: () => void;
  /**
   * Called when the user clicks ← in the chat header to return to the home state.
   * If not provided, no back button is shown.
   */
  onBack?: () => void;
  /** Called when the user clicks a recent conversation entry. */
  onOpenConversation?: (id: string) => void;
  /** Called when the user clicks "View all conversations". */
  onViewAllConversations?: () => void;
  /**
   * Pagination for the all-conversations list. When true, a "Load more" control is
   * shown at the bottom of the all-conversations view; clicking it fires
   * {@link onLoadMoreConversations}. The consumer appends the next page to
   * `recentConversations`.
   */
  hasMoreConversations?: boolean;
  /** Called when the user requests the next page in the all-conversations view. */
  onLoadMoreConversations?: () => void;
  /** True while the next page is loading — shows a spinner on the "Load more" control. */
  isLoadingMoreConversations?: boolean;
  /** True when older messages can be loaded for the active conversation. */
  hasMoreMessages?: boolean;
  /** True while an `onLoadMoreMessages` request is in flight. */
  isLoadingMoreMessages?: boolean;
  /** Fired when the user scrolls near the top of the chat — fetch older messages. */
  onLoadMoreMessages?: () => void;
  className?: string;
}

// ---------------------------------------------------------------------------
// TypingIndicator — three bouncing dots (same pattern as AiAssistantDrawer)
// ---------------------------------------------------------------------------

function SupportTypingIndicator() {
  return (
    <span
      className="flex items-center gap-1 py-1"
      aria-label="Assistant is thinking"
      role="status"
    >
      {[0, 150, 300].map((delay) => (
        <span
          key={delay}
          className="size-1.5 rounded-full bg-current animate-bounce"
          style={{ animationDelay: `${delay}ms` }}
          aria-hidden="true"
        />
      ))}
    </span>
  );
}

// ---------------------------------------------------------------------------
// StreamingStatus — optional status label with an animated "…" ellipsis
// (e.g. "Checking the help center" + animated dots), shown while streaming.
// ---------------------------------------------------------------------------

function StreamingStatus({ label }: { label?: string }) {
  // No label → the standard DS typing indicator (3 bouncing dots).
  if (!label) return <SupportTypingIndicator />;

  // With label → status text + the same DS typing dots: "Checking the help center • • •"
  return (
    <span
      className="flex items-center gap-1.5 text-sm text-muted-foreground"
      role="status"
      aria-label={`${label}…`}
    >
      <span>{label}</span>
      <SupportTypingIndicator />
    </span>
  );
}

// ---------------------------------------------------------------------------
// MessageBubble — renders a single message with optional rich content
// ---------------------------------------------------------------------------

interface MessageBubbleProps {
  message: SupportAgentMessage;
}

function MessageBubble({ message }: MessageBubbleProps) {
  const isUser = message.role === "user";
  const isEmpty = !message.content.trim();

  return (
    <div
      className={cn(
        "flex w-full flex-col",
        isUser ? "items-end" : "items-start",
      )}
    >
      {/* Text bubble */}
      <div
        className={cn(
          "max-w-[88%] px-3 py-2 text-sm",
          isUser
            ? "bg-primary text-primary-foreground"
            : "bg-muted text-foreground",
          message.isErrored && "bg-destructive/10 text-destructive",
        )}
        data-slot="support-message-bubble"
        data-role={message.role}
      >
        {isEmpty && message.isStreaming ? (
          <StreamingStatus label={message.streamingLabel} />
        ) : isUser ? (
          <span className="whitespace-pre-wrap break-words leading-relaxed">
            {message.content}
          </span>
        ) : (
          <div className="break-words text-sm leading-relaxed [&_a]:text-primary [&_a]:underline [&_p]:m-0 [&_p:not(:last-child)]:mb-2 [&_ul]:my-1 [&_ul]:list-disc [&_ul]:pl-4 [&_ol]:my-1 [&_ol]:list-decimal [&_ol]:pl-4 [&_li]:mb-0.5">
            <ReactMarkdown
              rehypePlugins={[rehypeRaw, [rehypeSanitize, defaultSchema]]}
              components={{
                a: ({ node, ...props }) => (
                  <a {...props} target="_blank" rel="noopener noreferrer" />
                ),
              }}
            >
              {message.content}
            </ReactMarkdown>
          </div>
        )}
        {message.isErrored && (
          <p className="mt-1 text-xs opacity-70">
            Failed to send. Please try again.
          </p>
        )}
      </div>

      {/* Rich content — only on assistant messages */}
      {!isUser && message.richContent && (
        <div className="w-full max-w-[88%]">
          <RichContentRenderer richContent={message.richContent} />
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// RichContentRenderer — picks the right card for richContent.type
// ---------------------------------------------------------------------------

interface RichContentRendererProps {
  richContent: SupportAgentRichContent;
}

function RichContentRenderer({ richContent }: RichContentRendererProps) {
  if (richContent.type === "step-guide") {
    return (
      <SupportStepGuideCard
        title={richContent.title}
        steps={richContent.steps}
      />
    );
  }

  if (richContent.type === "article") {
    return (
      <SupportArticleCard
        title={richContent.title}
        excerpt={richContent.excerpt}
        href={richContent.href}
        isExternal={richContent.isExternal}
      />
    );
  }

  return null;
}

// ---------------------------------------------------------------------------
// Local sub-components
// ---------------------------------------------------------------------------

/** Reusable close button — consistent across all panel header variants. */
function CloseButton({ onClick }: { onClick: () => void }) {
  return (
    <Button
      variant="ghost"
      size="icon"
      className="size-7 shrink-0"
      onClick={onClick}
      title="Close"
    >
      <X className="size-3.5" />
      <span className="sr-only">Close</span>
    </Button>
  );
}

/** Single conversation row — used in both home recents and all-conversations list. */
function ConversationRow({
  conv,
  onClick,
  className,
}: {
  conv: SupportAgentRecentConversation;
  onClick: () => void;
  className?: string;
}) {
  return (
    <button
      type="button"
      onClick={onClick}
      className={cn(
        "flex w-full items-center justify-between gap-2 text-left text-sm text-foreground hover:bg-muted/50",
        className,
      )}
    >
      <span className="flex-1 truncate">{conv.title}</span>
      <ChevronRight
        className="size-3.5 shrink-0 text-muted-foreground"
        aria-hidden="true"
      />
    </button>
  );
}

// ---------------------------------------------------------------------------
// SupportAgentPanel
// ---------------------------------------------------------------------------

export function SupportAgentPanel({
  open,
  onClose,
  messages = [],
  recentConversations,
  suggestedQuestions = [],
  conversationTitle,
  context,
  isStreaming = false,
  isLoading = false,
  onSendMessage,
  onAttachFile,
  onAttachImage,
  onNewChat,
  onBack,
  onOpenConversation,
  onViewAllConversations,
  hasMoreConversations = false,
  onLoadMoreConversations,
  isLoadingMoreConversations = false,
  hasMoreMessages,
  isLoadingMoreMessages,
  onLoadMoreMessages,
  className,
}: SupportAgentPanelProps) {
  const [inputValue, setInputValue] = React.useState("");
  const [showAllConversations, setShowAllConversations] = React.useState(false);
  const scrollRef = React.useRef<HTMLDivElement>(null);
  // Captures scrollHeight just before older messages prepend, to restore offset.
  const preLoadScrollHeightRef = React.useRef<number | null>(null);
  const prevLastMessageIdRef = React.useRef<string | undefined>(undefined);

  const hasMessages = messages.length > 0;

  // Chat header mode: has messages AND a conversation title
  const isChatMode = hasMessages && !!conversationTitle;

  // Reset "all conversations" view when panel closes
  React.useEffect(() => {
    if (!open) setShowAllConversations(false);
  }, [open]);

  // Scroll near the top of the chat thread → load older messages.
  const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {
    if (!hasMoreMessages || isLoadingMoreMessages || !onLoadMoreMessages) return;
    if (e.currentTarget.scrollTop <= 80) {
      preLoadScrollHeightRef.current = e.currentTarget.scrollHeight;
      onLoadMoreMessages();
    }
  };

  // Append (new message / open) → pin to bottom. Prepend (older history just
  // loaded, tail unchanged) → restore offset so the reader stays anchored.
  React.useLayoutEffect(() => {
    const el = scrollRef.current;
    if (!el || !hasMessages) return;

    if (preLoadScrollHeightRef.current !== null) {
      el.scrollTop = el.scrollHeight - preLoadScrollHeightRef.current;
      preLoadScrollHeightRef.current = null;
      prevLastMessageIdRef.current = messages[messages.length - 1]?.id;
      return;
    }

    const currentLastId = messages[messages.length - 1]?.id;
    if (prevLastMessageIdRef.current !== currentLastId) {
      el.scrollTop = el.scrollHeight;
    }
    prevLastMessageIdRef.current = currentLastId;
  }, [messages, hasMessages]);

  // Typing indicator adds DOM height — keep the view pinned to bottom.
  React.useLayoutEffect(() => {
    if (!isStreaming) return;
    const el = scrollRef.current;
    if (el) el.scrollTop = el.scrollHeight;
  }, [isStreaming]);

  const handleSend = React.useCallback(
    (text: string) => {
      onSendMessage?.(text);
      setInputValue("");
    },
    [onSendMessage],
  );

  const handleQuestionSelect = React.useCallback(
    (question: string) => {
      onSendMessage?.(question);
    },
    [onSendMessage],
  );

  const hasRecents = !!recentConversations?.length;
  // Home state shows only the 3 most recent; "View all" expands to the full list.
  const recentsPreview = React.useMemo(
    () => recentConversations?.slice(0, 3) ?? [],
    [recentConversations],
  );

  const handleViewAll = React.useCallback(() => {
    setShowAllConversations(true);
    onViewAllConversations?.(); // optional analytics callback
  }, [onViewAllConversations]);

  return (
    <Sheet open={open} onOpenChange={(o) => !o && onClose()}>
      <SheetContent
        side="right"
        showCloseButton={false}
        className={cn(
          "flex w-[400px] max-w-full flex-col gap-0 p-0",
          className,
        )}
        data-slot="support-agent-panel"
      >
        {/* ── Header ── */}
        <div className="shrink-0 border-b border-border px-3 py-2.5">
          {showAllConversations ? (
            /* All-conversations mode: [←]  All conversations  [✕] */
            <div className="flex items-center gap-1">
              <Button
                variant="ghost"
                size="icon"
                className="size-7 shrink-0"
                onClick={() => setShowAllConversations(false)}
                title="Back"
              >
                <ChevronLeft className="size-3.5" />
                <span className="sr-only">Back</span>
              </Button>
              <span className="flex-1 truncate px-1 text-sm font-medium text-foreground">
                All conversations
              </span>
              <CloseButton onClick={onClose} />
            </div>
          ) : isChatMode ? (
            /* Chat mode: [←]  Conversation title  [✕] */
            <div className="flex items-center gap-1">
              {onBack && (
                <Button
                  variant="ghost"
                  size="icon"
                  className="size-7 shrink-0"
                  onClick={onBack}
                  title="Back to conversations"
                >
                  <ChevronLeft className="size-3.5" />
                  <span className="sr-only">Back</span>
                </Button>
              )}
              <span className="flex-1 truncate px-1 text-sm font-medium text-foreground">
                {conversationTitle}
              </span>
              <CloseButton onClick={onClose} />
            </div>
          ) : (
            /* Home mode: [Bot icon]  Support Assistant  [✕] */
            <div className="flex items-center justify-between">
              <div className="flex items-center gap-2.5">
                <span className="flex size-7 shrink-0 items-center justify-center rounded-full border border-primary/40 bg-primary/10">
                  <Bot
                    className="size-3.5 text-foreground"
                    aria-hidden="true"
                  />
                </span>
                <span className="text-sm font-semibold text-foreground">
                  Support Assistant
                </span>
              </div>
              <CloseButton onClick={onClose} />
            </div>
          )}
          {/* Context chip — shown below header title in home and chat modes only */}
          {context && !showAllConversations && (
            <div className="mt-2">
              <SupportContextChip context={context} />
            </div>
          )}
        </div>

        {/* ── Content ── */}
        <div
          ref={scrollRef}
          onScroll={handleScroll}
          className="flex flex-1 flex-col overflow-y-auto"
        >
          {isLoading ? (
            /* Loading state */
            <div className="flex flex-1 items-center justify-center py-20">
              <div className="flex flex-col items-center gap-3">
                <Spinner size="lg" className="text-muted-foreground" />
                <p className="text-sm text-muted-foreground">Loading…</p>
              </div>
            </div>
          ) : showAllConversations ? (
            /* All conversations — full scrollable list (Jira Rovo pattern) */
            <div className="flex flex-col">
              {recentConversations?.length ? (
                <>
                  {recentConversations.map((conv) => (
                    <ConversationRow
                      key={conv.id}
                      conv={conv}
                      onClick={() => {
                        setShowAllConversations(false);
                        onOpenConversation?.(conv.id);
                      }}
                      className="border-b border-border px-4 py-3"
                    />
                  ))}
                  {hasMoreConversations && (
                    <div className="border-t border-border p-3">
                      <Button
                        variant="outline"
                        size="sm"
                        className="w-full"
                        disabled={isLoadingMoreConversations}
                        onClick={onLoadMoreConversations}
                      >
                        {isLoadingMoreConversations ? "Loading..." : "Load more"}
                      </Button>
                    </div>
                  )}
                </>
              ) : (
                <p className="p-4 text-sm text-muted-foreground">
                  No conversations yet.
                </p>
              )}
            </div>
          ) : !hasMessages ? (
            /* Home state — Rovo pattern: New Chat CTA + Recents + Suggested */
            <div className="flex flex-col gap-5 p-4">
              {/* New Chat — prominent CTA button */}
              {onNewChat && (
                <Button
                  variant="outline"
                  className="w-full justify-start gap-2 text-sm font-medium"
                  onClick={onNewChat}
                  disabled={isLoading}
                >
                  <SquarePen className="size-3.5" aria-hidden="true" />
                  New chat
                </Button>
              )}

              {/* Recents — 3 most recent conversations */}
              {hasRecents && (
                <div className="flex flex-col gap-1">
                  <p className="px-1 text-xs font-medium uppercase tracking-wide text-muted-foreground">
                    Recents
                  </p>
                  <div className="flex flex-col">
                    {recentsPreview.map((conv) => (
                      <ConversationRow
                        key={conv.id}
                        conv={conv}
                        onClick={() => onOpenConversation?.(conv.id)}
                        className="px-1 py-2.5"
                      />
                    ))}
                  </div>
                  <Button
                    variant="ghost"
                    size="sm"
                    onClick={handleViewAll}
                    className="h-auto w-fit gap-0.5 px-1 py-1 text-xs text-muted-foreground hover:bg-transparent hover:text-foreground"
                  >
                    View all conversations
                    <ChevronRight className="size-3.5" aria-hidden="true" />
                  </Button>
                </div>
              )}

              {/* Suggested — conversation starters */}
              {suggestedQuestions.length > 0 && (
                <div className="flex flex-col gap-1.5">
                  <p className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
                    Suggested
                  </p>
                  <div className="flex flex-col gap-1.5">
                    {suggestedQuestions.map((q) => (
                      <SupportSuggestedQuestion
                        key={q}
                        question={q}
                        onSelect={handleQuestionSelect}
                      />
                    ))}
                  </div>
                </div>
              )}

              {/* Fallback — nothing to show */}
              {!onNewChat && !hasRecents && !suggestedQuestions.length && (
                <p className="text-sm text-muted-foreground">
                  How can I help you today?
                </p>
              )}
            </div>
          ) : (
            /* Chat thread */
            <div className="flex flex-col gap-3 p-4">
              {isLoadingMoreMessages && (
                <div className="flex justify-center py-1">
                  <Spinner size="sm" className="text-muted-foreground" />
                </div>
              )}
              {messages.map((msg) => (
                <MessageBubble key={msg.id} message={msg} />
              ))}
              {/* Streaming indicator — shown when last message is from the user */}
              {isStreaming &&
                messages[messages.length - 1]?.role === "user" && (
                  <div className="flex justify-start">
                    <div className="bg-muted px-3 py-2 text-muted-foreground">
                      <SupportTypingIndicator />
                    </div>
                  </div>
                )}
            </div>
          )}
        </div>

        {/* ── Footer ── */}
        <div className="shrink-0 border-t border-border p-3">
          <ChatInputArea
            value={inputValue}
            onChange={setInputValue}
            onSend={handleSend}
            onAttachFile={onAttachFile}
            onAttachImage={onAttachImage}
            disabled={isLoading || isStreaming}
            placeholder="Ask anything…"
            showMarkdownToolbar
          />
        </div>
      </SheetContent>
    </Sheet>
  );
}
