import * as React from "react";
import {
  Bot,
  UserRound,
  MessageCircle,
  X,
  ChevronDown,
  Send,
  Smile,
  Paperclip,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { resolveBrandVars } from "@/lib/colors";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { MarkdownContent } from "@/components/ui/markdown-content";

/**
 * ChatWidget Primitives — WealthX DS (Atoms)
 *
 * Atomic building blocks for the embeddable broker website chat widget.
 * All atoms are pure display components — no API calls, no state beyond local UI.
 *
 * Exports:
 *   ChatWidgetLauncher      — Floating action button (open/close)
 *   ChatWidgetHeader        — Gradient branded header
 *   ChatWidgetMessage       — Message bubble (bot | user | system)
 *   TypingDots              — Bare three-bouncing-dots animation (shared atom)
 *   ChatWidgetTypingIndicator — Animated 3-dot indicator
 *   ChatWidgetInputBar      — Footer input with emoji/attachment/send
 */

// ---------------------------------------------------------------------------
// ChatWidgetLauncher
// ---------------------------------------------------------------------------

export interface ChatWidgetLauncherProps {
  /** Whether the chat window is currently open. */
  isOpen: boolean;
  onClick: () => void;
  /**
   * Solid brand color (hex) for the button background. Omit to inherit
   * `--primary` from the nearest ThemeProvider. When set, the icon color is
   * derived from it so it stays readable on light brand colors.
   */
  brandColor?: string;
  /** Number of unread messages — shows a red badge when > 0 and chat is closed. */
  unreadCount?: number;
  className?: string;
}

export function ChatWidgetLauncher({
  isOpen,
  onClick,
  brandColor,
  unreadCount,
  className,
}: ChatWidgetLauncherProps) {
  return (
    <button
      type="button"
      aria-label={isOpen ? "Close chat" : "Open chat"}
      onClick={onClick}
      className={cn(
        "relative flex size-14 items-center justify-center shadow-lg transition-all",
        "rounded-full", // intentional: circular FAB shape
        "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
        className,
      )}
      style={
        {
          ...resolveBrandVars(brandColor),
          backgroundColor: "var(--primary)",
        } as React.CSSProperties
      }
    >
      {!isOpen && unreadCount && unreadCount > 0 ? (
        <Badge
          variant="destructive"
          className="absolute -right-1 -top-1 size-5 justify-center bg-destructive px-0 py-0 text-[10px] font-semibold text-destructive-foreground"
        >
          {unreadCount > 9 ? "9+" : unreadCount}
        </Badge>
      ) : null}
      {isOpen ? (
        <X className="size-6 text-primary-foreground" />
      ) : (
        <MessageCircle className="size-6 text-primary-foreground" />
      )}
    </button>
  );
}

// ---------------------------------------------------------------------------
// ChatWidgetHeader
// ---------------------------------------------------------------------------

export interface ChatWidgetHeaderProps {
  brokerName: string;
  subtitle?: string;
  /** Gradient start color. */
  gradientFrom?: string;
  /** Gradient end color. */
  gradientTo?: string;
  onMinimize?: () => void;
  className?: string;
}

export function ChatWidgetHeader({
  brokerName,
  subtitle = "Feel free to chat with us",
  gradientFrom,
  gradientTo,
  onMinimize,
  className,
}: ChatWidgetHeaderProps) {
  const hasGradient = gradientFrom && gradientTo;

  return (
    <div
      className={cn(
        "flex items-start justify-between px-4 py-3",
        !hasGradient && "bg-primary",
        className,
      )}
      style={
        hasGradient
          ? {
              background: `linear-gradient(135deg, ${gradientFrom}, ${gradientTo})`,
            }
          : undefined
      }
    >
      <div className="flex flex-col gap-0.5">
        <p className="text-body-large font-semibold text-primary-foreground">
          {brokerName}
        </p>
        {subtitle && (
          <p className="text-body-small text-primary-foreground/70">
            {subtitle}
          </p>
        )}
      </div>
      <div className="flex items-center gap-1">
        {onMinimize && (
          <Button
            variant="ghost"
            size="icon-sm"
            aria-label="Minimise chat"
            onClick={onMinimize}
            className="text-primary-foreground/70 hover:bg-primary-foreground/10 hover:text-primary-foreground"
          >
            <ChevronDown className="size-4" />
          </Button>
        )}
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// ChatWidgetMessage
// ---------------------------------------------------------------------------

export type ChatWidgetMessageRole = "bot" | "advisor" | "user" | "system";

export interface ChatWidgetMessageProps {
  role: ChatWidgetMessageRole;
  content: string;
  timestamp?: string;
  /** True while the bot response is still streaming in — shows TypingIndicator instead. */
  isStreaming?: boolean;
  /**
   * How to render `content`. `"plain"` (default) renders the raw string.
   * `"markdown"` renders it as sanitized markdown (headings, lists, links,
   * tables, code) — use for AI / assistant responses.
   */
  format?: "plain" | "markdown";
  className?: string;
}

export function ChatWidgetMessage({
  role,
  content,
  timestamp,
  isStreaming,
  format = "plain",
  className,
}: ChatWidgetMessageProps) {
  if (role === "system") {
    return (
      <div className={cn("flex items-center justify-center py-2", className)}>
        <span className="text-body-small text-muted-foreground">{content}</span>
      </div>
    );
  }

  const isLeft = role === "bot" || role === "advisor";

  return (
    <div
      className={cn(
        "flex gap-2",
        isLeft ? "items-start" : "flex-row-reverse items-start",
        className,
      )}
    >
      {isLeft && (
        <Avatar className="size-7">
          <AvatarFallback
            className={
              role === "advisor" ? "bg-primary/15 text-foreground" : undefined
            }
          >
            {role === "advisor" ? (
              <UserRound className="size-3.5" />
            ) : (
              <Bot className="size-3.5" />
            )}
          </AvatarFallback>
        </Avatar>
      )}
      <div
        className={cn(
          "flex max-w-[80%] flex-col gap-1",
          !isLeft && "items-end",
        )}
      >
        <div
          className={cn(
            "px-3 py-2 text-body-medium",
            isLeft
              ? "border border-border bg-card text-card-foreground shadow-sm"
              : "text-primary-foreground",
          )}
          style={!isLeft ? { backgroundColor: "var(--primary)" } : undefined}
        >
          {isStreaming ? (
            <ChatWidgetTypingIndicator />
          ) : format === "markdown" ? (
            <MarkdownContent content={content} />
          ) : (
            content
          )}
        </div>
        {timestamp && !isStreaming && (
          <span className="text-[10px] text-muted-foreground">{timestamp}</span>
        )}
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// TypingDots
// ---------------------------------------------------------------------------

export interface TypingDotsProps {
  /**
   * Size preset. `"default"` = size-1.5 rounded dots at /60 opacity (chat
   * widget); `"sm"` = size-1 square dots at /70 opacity (copilot thinking
   * steps). Bundles dot size, gap, shape and opacity so call sites stay
   * pixel-identical to their prior hand-rolled markup.
   */
  size?: "default" | "sm";
  className?: string;
}

/**
 * Bare three-bouncing-dots animation, shared by `ChatWidgetTypingIndicator`
 * and the copilot `CopilotThinkingSteps`. Renders an `aria-hidden` span — the
 * accessible status text is owned by the consuming component.
 */
export function TypingDots({ size = "default", className }: TypingDotsProps) {
  const sm = size === "sm";
  return (
    <span
      className={cn(
        "flex shrink-0 items-center",
        sm ? "gap-0.5" : "gap-1",
        className,
      )}
      aria-hidden="true"
    >
      {[0, 1, 2].map((i) => (
        <span
          key={i}
          className={cn(
            "animate-bounce",
            sm
              ? "size-1 bg-muted-foreground/70"
              : "size-1.5 rounded-full bg-muted-foreground/60",
          )}
          style={{ animationDelay: `${i * 0.15}s` }}
        />
      ))}
    </span>
  );
}

// ---------------------------------------------------------------------------
// ChatWidgetTypingIndicator
// ---------------------------------------------------------------------------

export interface ChatWidgetTypingIndicatorProps {
  /**
   * Optional label shown beside the animation, e.g. "Analysing your file…".
   * When set it also becomes the accessible status text.
   */
  label?: string;
  /**
   * Visual style. `"dots"` (default) = three bouncing dots for live typing.
   * `"shimmer"` = a pulsing bar for a pre-stream "thinking" state.
   */
  variant?: "dots" | "shimmer";
  className?: string;
}

export function ChatWidgetTypingIndicator({
  label,
  variant = "dots",
  className,
}: ChatWidgetTypingIndicatorProps) {
  return (
    <div
      role="status"
      aria-label={label ?? "Typing"}
      className={cn("flex items-center gap-2 py-0.5", className)}
    >
      {variant === "shimmer" ? (
        <span
          className="h-2.5 w-16 animate-pulse bg-muted-foreground/25"
          aria-hidden="true"
        />
      ) : (
        <TypingDots />
      )}
      {label && (
        <span className="text-body-small text-muted-foreground">{label}</span>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// ChatWidgetInputBar
// ---------------------------------------------------------------------------

export interface ChatWidgetInputBarProps {
  value: string;
  onChange: (value: string) => void;
  onSend: (value: string) => void;
  disabled?: boolean;
  placeholder?: string;
  className?: string;
}

export function ChatWidgetInputBar({
  value,
  onChange,
  onSend,
  disabled,
  placeholder = "Type your message here",
  className,
}: ChatWidgetInputBarProps) {
  const hasText = value.trim().length > 0;

  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === "Enter" && !e.shiftKey && hasText && !disabled) {
      e.preventDefault();
      onSend(value);
    }
  };

  return (
    <div
      className={cn(
        "flex items-center gap-2 border-t border-border bg-muted/30 px-3 py-2.5",
        className,
      )}
    >
      <Button
        variant="ghost"
        size="icon-sm"
        aria-label="Add emoji"
        disabled={disabled}
        className="shrink-0 text-muted-foreground hover:text-foreground"
      >
        <Smile className="size-5" />
      </Button>
      <Button
        variant="ghost"
        size="icon-sm"
        aria-label="Add attachment"
        disabled={disabled}
        className="shrink-0 text-muted-foreground hover:text-foreground"
      >
        <Paperclip className="size-5" />
      </Button>
      <Input
        value={value}
        onChange={(e) => onChange(e.target.value)}
        onKeyDown={handleKeyDown}
        placeholder={placeholder}
        disabled={disabled}
        className="flex-1 border-0 bg-transparent px-0 shadow-none focus-visible:ring-0 text-body-medium placeholder:text-muted-foreground/60"
      />
      <Button
        type="button"
        variant="ghost"
        size="icon-sm"
        aria-label="Send message"
        disabled={disabled || !hasText}
        onClick={() => hasText && !disabled && onSend(value)}
        className="shrink-0"
      >
        <Send className="size-4" />
      </Button>
    </div>
  );
}
