import * as React from "react";
import { Clock, Plus } from "lucide-react";
import { cn } from "@/lib/utils";
import {
  ChatWidgetHeader,
  ChatWidgetMessage,
} from "@/components/ui/chat-widget-primitives";
import { ChatInputArea } from "@/components/ui/chat-input-area";
import { Button } from "@/components/ui/button";
import {
  CopilotChatHistory,
  type CopilotConversation,
} from "@/components/ui/copilot-chat-history";
import {
  CopilotErrorMessage,
  CopilotRateLimitMessage,
  CopilotSourceCitation,
  CopilotThinkingSteps,
  type CopilotErrorMessageProps,
  type CopilotRateLimitMessageProps,
  type CopilotSource,
} from "@/components/ui/copilot-primitives";
import {
  CopilotActionCard,
  type CopilotActionCardProps,
} from "@/components/ui/copilot-action-card";
import {
  CopilotPlanCard,
  type CopilotPlanCardProps,
} from "@/components/ui/copilot-plan-card";
import {
  CopilotDataCard,
  type CopilotDataCardProps,
} from "@/components/ui/copilot-data-card";
import {
  CopilotSuggestionCard,
  type CopilotSuggestionCardProps,
} from "@/components/ui/copilot-suggestion-card";
import {
  CopilotContextCard,
  type CopilotContextCardProps,
} from "@/components/ui/copilot-context-card";
import {
  CopilotMeetingNoteCard,
  type CopilotMeetingNoteCardProps,
} from "@/components/ui/copilot-meeting-note-card";
import {
  CopilotMeetingRecordPrompt,
  type CopilotMeetingRecordPromptProps,
} from "@/components/ui/copilot-meeting-record-prompt";
import { CopilotConnectionState } from "@/components/ui/copilot-connection-state";
import { CopilotAuthState } from "@/components/ui/copilot-auth-state";
import {
  CopilotEmptyState,
  type CopilotSuggestedPrompt,
} from "@/components/ui/copilot-empty-state";

/**
 * CopilotPanel — WealthX DS (Template)
 *
 * The full broker Copilot extension panel: a branded header, a body that
 * switches between the connection / signed-out / empty / chat states, and a
 * message composer. The chat thread composes every Copilot response atom and
 * molecule. Layout/composition only — driven by mock/placeholder data via props.
 */

export type CopilotPanelState =
  | "not-installed"
  | "connecting"
  | "signed-out"
  | "empty"
  | "chat";

interface CopilotThreadMessage {
  role: "bot" | "advisor" | "user" | "system";
  content: string;
  format?: "plain" | "markdown";
  timestamp?: string;
  /** Source chips rendered beneath the message. */
  sources?: CopilotSource[];
}

export type CopilotThreadItem =
  | ({ kind: "message" } & CopilotThreadMessage)
  | {
      kind: "thinking";
      steps?: string[];
      isThinking?: boolean;
      defaultExpanded?: boolean;
    }
  | ({ kind: "action" } & CopilotActionCardProps)
  | ({ kind: "plan" } & CopilotPlanCardProps)
  | ({ kind: "data" } & CopilotDataCardProps)
  | ({ kind: "suggestion" } & CopilotSuggestionCardProps)
  | ({ kind: "context" } & CopilotContextCardProps)
  | ({ kind: "meeting-note" } & CopilotMeetingNoteCardProps)
  | ({ kind: "meeting-record" } & CopilotMeetingRecordPromptProps)
  | ({ kind: "error" } & CopilotErrorMessageProps)
  | ({ kind: "rate-limit" } & CopilotRateLimitMessageProps);

export interface CopilotPanelProps {
  /** Which surface to show. Defaults to "chat". */
  state?: CopilotPanelState;
  brokerName?: string;
  subtitle?: string;
  onMinimize?: () => void;

  // chat thread
  items?: CopilotThreadItem[];

  // connection state
  onInstall?: () => void;
  onContinue?: () => void;

  // signed-out state
  onSignIn?: () => void;

  // empty state
  prompts?: CopilotSuggestedPrompt[];

  // composer (chat state)
  inputValue?: string;
  onInputChange?: (value: string) => void;
  onSend?: (value: string) => void;
  inputPlaceholder?: string;
  inputDisabled?: boolean;
  /** Show the markdown formatting toolbar in the composer. @default true */
  showMarkdownToolbar?: boolean;
  /** When provided, shows an attach-file button in the composer. */
  onAttachFile?: (files: FileList) => void;

  // chat history (opens as a bottom sheet from the history icon)
  conversations?: CopilotConversation[];
  currentConversationId?: string;
  onSelectConversation?: (id: string) => void;
  onRenameConversation?: (id: string) => void;
  onDeleteConversation?: (id: string) => void;
  /** When provided, shows a "new chat" (+) control next to the history icon. */
  onNewChat?: () => void;

  className?: string;
}

/** A card that sits on the right (user-supplied) rather than the agent side. */
const RIGHT_ALIGNED_KINDS = new Set(["context"]);

/** Maps a card-style thread item's `kind` to the component that renders it. */
const CARD_BY_KIND: Record<string, React.ComponentType<any>> = {
  action: CopilotActionCard,
  plan: CopilotPlanCard,
  data: CopilotDataCard,
  suggestion: CopilotSuggestionCard,
  context: CopilotContextCard,
  "meeting-note": CopilotMeetingNoteCard,
  "meeting-record": CopilotMeetingRecordPrompt,
  error: CopilotErrorMessage,
  "rate-limit": CopilotRateLimitMessage,
};

function ThreadItem({ item }: { item: CopilotThreadItem }) {
  if (item.kind === "message") {
    const { kind, sources, ...message } = item;
    void kind;
    const isRight = message.role === "user";
    return (
      <div className="flex flex-col gap-1">
        <ChatWidgetMessage {...message} />
        {sources && sources.length > 0 && (
          <div className={cn("flex", isRight ? "justify-end" : "pl-9")}>
            <CopilotSourceCitation sources={sources} />
          </div>
        )}
      </div>
    );
  }

  if (item.kind === "thinking") {
    return (
      <CopilotThinkingSteps
        steps={item.steps ?? ["Thinking…"]}
        isThinking={item.isThinking}
        defaultExpanded={item.defaultExpanded}
      />
    );
  }

  // Card-style items: look the renderer up by kind and align by side.
  const { kind, ...props } = item;
  const Card = CARD_BY_KIND[kind];
  const isRight = RIGHT_ALIGNED_KINDS.has(kind);

  return (
    <div className={cn("flex", isRight ? "justify-end" : "justify-start")}>
      <div className="w-[88%]">
        <Card {...props} />
      </div>
    </div>
  );
}

export function CopilotPanel({
  state = "chat",
  brokerName = "WealthX Copilot",
  subtitle = "Your AI assistant",
  onMinimize,
  items = [],
  onInstall,
  onContinue,
  onSignIn,
  prompts,
  inputValue = "",
  onInputChange,
  onSend,
  inputPlaceholder,
  inputDisabled,
  showMarkdownToolbar = true,
  onAttachFile,
  conversations,
  currentConversationId,
  onSelectConversation,
  onRenameConversation,
  onDeleteConversation,
  onNewChat,
  className,
}: CopilotPanelProps) {
  const [historyOpen, setHistoryOpen] = React.useState(false);

  return (
    <div
      className={cn(
        "relative flex h-full w-full flex-col overflow-hidden bg-background",
        className,
      )}
    >
      <ChatWidgetHeader
        brokerName={brokerName}
        subtitle={subtitle}
        onMinimize={onMinimize}
      />

      <div className="flex-1 overflow-y-auto">
        {(state === "not-installed" || state === "connecting") && (
          <CopilotConnectionState
            className="h-full border-0"
            status={state}
            onInstall={onInstall}
            onContinue={onContinue}
          />
        )}

        {state === "signed-out" && (
          <CopilotAuthState className="h-full border-0" onSignIn={onSignIn} />
        )}

        {state === "empty" && (
          <CopilotEmptyState className="h-full border-0" prompts={prompts} />
        )}

        {state === "chat" && (
          <div className="flex flex-col gap-3 p-4">
            {items.map((item, i) => (
              <ThreadItem key={i} item={item} />
            ))}
          </div>
        )}
      </div>

      {(state === "chat" || state === "empty") && (
        <>
          <div className="flex items-center justify-end gap-1 border-t border-border px-3 py-1.5">
            <Button
              type="button"
              variant="ghost"
              size="sm"
              onClick={() => setHistoryOpen(true)}
            >
              <Clock className="size-4" />
              History
            </Button>
            {onNewChat && (
              <Button
                type="button"
                variant="ghost"
                size="sm"
                onClick={onNewChat}
              >
                <Plus className="size-4" />
                New Chat
              </Button>
            )}
          </div>
          <div className="p-2">
            <ChatInputArea
              value={inputValue}
              onChange={onInputChange ?? (() => {})}
              onSend={onSend ?? (() => {})}
              placeholder={inputPlaceholder}
              disabled={inputDisabled}
              showMarkdownToolbar={showMarkdownToolbar}
              onAttachFile={onAttachFile}
            />
          </div>
        </>
      )}

      {/* Chat history — bottom sheet scoped to the panel. Hand-rolled rather
          than the DS Sheet because Sheet portals to document.body and can't be
          contained inside the panel's own bounds. */}
      {historyOpen && (
        <div className="absolute inset-0 z-10 flex flex-col justify-end">
          <button
            type="button"
            aria-label="Close chat history"
            className="absolute inset-0 bg-foreground/50 duration-200 animate-in fade-in"
            onClick={() => setHistoryOpen(false)}
          />
          <div className="relative h-[78%] overflow-hidden border-t border-border bg-background shadow-lg duration-200 animate-in slide-in-from-bottom">
            <CopilotChatHistory
              conversations={conversations ?? []}
              currentId={currentConversationId}
              onSelect={(id) => {
                onSelectConversation?.(id);
                setHistoryOpen(false);
              }}
              onRename={onRenameConversation}
              onDelete={onDeleteConversation}
              onClose={() => setHistoryOpen(false)}
            />
          </div>
        </div>
      )}
    </div>
  );
}
