import * as React from "react";
import {
  CircleAlert,
  RefreshCw,
  Zap,
  Clock,
  FileText,
  UserRound,
  Briefcase,
  CalendarClock,
  ExternalLink,
  Check,
  ChevronDown,
  Sparkles,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert";
import { Chip } from "@/components/ui/chip";
import { TypingDots } from "@/components/ui/chat-widget-primitives";

/**
 * Copilot Primitives — WealthX DS (Atoms)
 *
 * Display-only response atoms for the broker Copilot extension chat surface.
 * Each renders one "response case" the agent can return. No API calls, no
 * state beyond local UI — data in via props, events out via callbacks.
 *
 * Composes existing DS primitives (Alert, Chip, Button) rather than re-styling
 * raw markup, so they inherit the system's variants, tokens and sharp corners.
 *
 * Exports:
 *   CopilotErrorMessage     — failed response + Retry          (Alert destructive)
 *   CopilotRateLimitMessage — usage/quota exhausted            (Alert warning)
 *   CopilotSourceCitation   — "Based on:" data-source chips     (Chip)
 */

// ---------------------------------------------------------------------------
// CopilotErrorMessage
// ---------------------------------------------------------------------------

export interface CopilotErrorMessageProps {
  /** Headline shown to the user. Defaults to a generic failure message. */
  message?: string;
  /** Optional technical/contextual reason shown under the headline. */
  detail?: string;
  /** When provided, renders a Retry button that calls this. */
  onRetry?: () => void;
  /** Label for the retry button. Defaults to "Retry". */
  retryLabel?: string;
  className?: string;
}

export function CopilotErrorMessage({
  message = "Something went wrong generating a response.",
  detail,
  onRetry,
  retryLabel = "Retry",
  className,
}: CopilotErrorMessageProps) {
  return (
    <Alert variant="destructive" className={className}>
      <CircleAlert />
      <AlertTitle>{message}</AlertTitle>
      {(detail || onRetry) && (
        <AlertDescription>
          {detail && <p>{detail}</p>}
          {onRetry && (
            <Button
              type="button"
              variant="outline"
              size="sm"
              onClick={onRetry}
              className="mt-1 h-7 gap-1.5"
            >
              <RefreshCw className="size-3.5" aria-hidden="true" />
              {retryLabel}
            </Button>
          )}
        </AlertDescription>
      )}
    </Alert>
  );
}

// ---------------------------------------------------------------------------
// CopilotRateLimitMessage
// ---------------------------------------------------------------------------

export interface CopilotRateLimitMessageProps {
  /** Headline. Defaults to a usage-limit message. */
  message?: string;
  /** Human-readable reset hint, e.g. "in 12 minutes" or "at 2:30 PM". */
  resetLabel?: string;
  /** When provided, renders an upgrade/primary action. */
  onUpgrade?: () => void;
  /** Label for the upgrade action. Defaults to "Upgrade plan". */
  upgradeLabel?: string;
  className?: string;
}

export function CopilotRateLimitMessage({
  message = "You've reached your Copilot usage limit.",
  resetLabel,
  onUpgrade,
  upgradeLabel = "Upgrade plan",
  className,
}: CopilotRateLimitMessageProps) {
  return (
    <Alert variant="warning" className={className}>
      <Zap />
      <AlertTitle>{message}</AlertTitle>
      {(resetLabel || onUpgrade) && (
        <AlertDescription>
          {resetLabel && (
            <p className="flex items-center gap-1">
              <Clock className="size-3.5" aria-hidden="true" />
              Resets {resetLabel}
            </p>
          )}
          {onUpgrade && (
            <Button
              type="button"
              size="sm"
              onClick={onUpgrade}
              className="mt-1 h-7"
            >
              {upgradeLabel}
            </Button>
          )}
        </AlertDescription>
      )}
    </Alert>
  );
}

// ---------------------------------------------------------------------------
// CopilotSourceCitation
// ---------------------------------------------------------------------------

export type CopilotSourceType = "contact" | "deal" | "document" | "appointment";

export interface CopilotSource {
  /** Display text, e.g. "Jordan Avery" or "Loan #4821". */
  label: string;
  /** Drives the leading icon. Defaults to "document". */
  type?: CopilotSourceType;
  /** When provided, the chip becomes interactive and calls this. */
  onClick?: () => void;
}

export interface CopilotSourceCitationProps {
  sources: CopilotSource[];
  /** Leading label. Defaults to "Based on". */
  label?: string;
  className?: string;
}

const SOURCE_ICON: Record<
  CopilotSourceType,
  React.ComponentType<{ className?: string }>
> = {
  contact: UserRound,
  deal: Briefcase,
  document: FileText,
  appointment: CalendarClock,
};

export function CopilotSourceCitation({
  sources,
  label = "Based on",
  className,
}: CopilotSourceCitationProps) {
  if (sources.length === 0) return null;

  return (
    <div
      className={cn(
        "flex flex-wrap items-center gap-1.5 text-body-small text-muted-foreground",
        className,
      )}
    >
      <span className="shrink-0">{label}:</span>
      {sources.map((source, i) => {
        const Icon = SOURCE_ICON[source.type ?? "document"];
        const interactive = Boolean(source.onClick);
        return (
          <Chip
            key={i}
            variant="outline"
            className={cn(
              "max-w-[180px] gap-1 font-normal",
              interactive &&
                "cursor-pointer transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
            )}
            {...(interactive
              ? {
                  role: "button",
                  tabIndex: 0,
                  onClick: source.onClick,
                  onKeyDown: (e: React.KeyboardEvent<HTMLSpanElement>) => {
                    if (e.key === "Enter" || e.key === " ") {
                      e.preventDefault();
                      source.onClick?.();
                    }
                  },
                }
              : {})}
          >
            <Icon className="size-3 text-muted-foreground" />
            <span className="truncate">{source.label}</span>
            {interactive && (
              <ExternalLink className="size-3 text-muted-foreground" />
            )}
          </Chip>
        );
      })}
    </div>
  );
}

// ---------------------------------------------------------------------------
// CopilotThinkingSteps
// ---------------------------------------------------------------------------

export interface CopilotThinkingStepsProps {
  /**
   * Reasoning steps. While `isThinking`, the last entry is the in-progress step
   * (animated dots) and earlier ones are completed; otherwise all are completed.
   */
  steps: string[];
  /**
   * Collapsed summary line. Defaults to the live step while thinking, or
   * "Thought process" once done.
   */
  summary?: string;
  /** Reasoning still in progress — animated, last step active. @default true */
  isThinking?: boolean;
  /** Start expanded. @default false */
  defaultExpanded?: boolean;
  className?: string;
}

/**
 * Agent "thinking" disclosure (Claude/GPT style): a collapsed one-line summary
 * by default; clicking the chevron expands the full reasoning trace. While
 * `isThinking`, the summary tracks the live step and the last step animates.
 * Ports the policy-AI thinking-steps pattern into a shared, collapsible atom.
 */
export function CopilotThinkingSteps({
  steps,
  summary,
  isThinking = true,
  defaultExpanded = false,
  className,
}: CopilotThinkingStepsProps) {
  const [expanded, setExpanded] = React.useState(defaultExpanded);
  if (steps.length === 0) return null;

  const current = steps[steps.length - 1];

  // While the agent is still reasoning, show a plain live line (the current
  // step with animated dots) — no disclosure chevron, nothing to expand yet.
  if (isThinking) {
    const liveText = summary ?? current;
    return (
      <div
        role="status"
        aria-label={liveText}
        className={cn(
          "flex items-center gap-2 self-start px-1 py-1 text-body-small text-muted-foreground",
          className,
        )}
      >
        <TypingDots size="sm" />
        <span key={liveText} className="animate-in fade-in leading-snug">
          {liveText}
        </span>
      </div>
    );
  }

  // Once done, collapse into a "Thought process" disclosure that expands the
  // full (completed) reasoning trace.
  const summaryText = summary ?? "Thought process";

  return (
    <div
      role="status"
      aria-label={summaryText}
      className={cn("flex flex-col", className)}
    >
      <button
        type="button"
        onClick={() => setExpanded((v) => !v)}
        aria-expanded={expanded}
        className="flex items-center gap-2 self-start px-1 py-1 text-body-small text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
      >
        <Sparkles className="size-3.5 shrink-0" aria-hidden="true" />
        <span className="leading-snug">{summaryText}</span>
        <ChevronDown
          className={cn(
            "size-3.5 shrink-0 transition-transform duration-200",
            expanded && "rotate-180",
          )}
          aria-hidden="true"
        />
      </button>

      {expanded && (
        <ol className="ml-2.5 flex flex-col gap-1.5 border-l border-border py-1 pl-3">
          {steps.map((step, i) => (
            <li
              key={i}
              className="flex items-start gap-2 text-body-small leading-snug text-muted-foreground"
            >
              <Check
                className="mt-0.5 size-3 shrink-0 text-muted-foreground/70"
                aria-hidden="true"
              />
              <span>{step}</span>
            </li>
          ))}
        </ol>
      )}
    </div>
  );
}
