import * as React from "react";
import { Check, Circle, CircleAlert, Play, RefreshCw, Square } from "lucide-react";
import { cn } from "@/lib/utils";
import {
  Card,
  CardHeader,
  CardTitle,
  CardDescription,
  CardAction,
  CardContent,
  CardFooter,
} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Spinner } from "@/components/ui/spinner";
import { TypingDots } from "@/components/ui/chat-widget-primitives";

/**
 * CopilotPlanCard — WealthX DS (Molecule)
 *
 * Renders an agentic plan the broker Copilot proposes: a named plan with a
 * description and an ordered list of steps that execute one-by-one. Each step
 * shows its own status (pending / running / done / failed) and the card carries
 * an "Execute Plan" affordance below the steps.
 *
 * Composes Card + Button + Badge + Spinner + TypingDots. Pure display: the host
 * wires onExecute to the real side-effect and drives `status` + per-step
 * `status` as execution progresses.
 */

export type CopilotPlanStepStatus = "pending" | "running" | "done" | "failed";

export interface CopilotPlanStep {
  /** Step label, e.g. "Read the loan application details from WealthX". */
  label: string;
  /** Optional detail shown under the label. */
  description?: string;
  /** Execution status of this step. Defaults to "pending". */
  status?: CopilotPlanStepStatus;
}

export type CopilotPlanStatus = "idle" | "running" | "done" | "failed";

export interface CopilotPlanCardProps {
  /** Plan name shown as the card title, e.g. "Quickli Scenario Sync". */
  title: string;
  /** What the plan does. */
  description?: string;
  /** Ordered steps, executed one-by-one. */
  steps: CopilotPlanStep[];
  /** Overall plan lifecycle. Defaults to "idle". */
  status?: CopilotPlanStatus;
  /** Runs the plan. When provided, renders the execute / retry button. */
  onExecute?: () => void;
  /**
   * Stops an in-progress run. When provided, the running state swaps the
   * disabled "Executing…" button for a clickable Stop button so the host can
   * abort execution.
   */
  onCancel?: () => void;
  /** Label for the idle execute button. Defaults to "Execute Plan". */
  executeLabel?: string;
  /** Label while the plan is running. Defaults to "Executing…". */
  runningLabel?: string;
  /** Label for the retry button after a failed run. Defaults to "Retry Plan". */
  retryLabel?: string;
  /** Label for the stop button while running. Defaults to "Stop". */
  cancelLabel?: string;
  className?: string;
}

const PLAN_BADGE: Record<
  Exclude<CopilotPlanStatus, "idle">,
  { label: string; variant: "warning" | "success" | "destructive" }
> = {
  running: { label: "Running…", variant: "warning" },
  done: { label: "Completed", variant: "success" },
  failed: { label: "Failed", variant: "destructive" },
};

const STEP_STATUS: Record<
  CopilotPlanStepStatus,
  { srLabel: string; labelClass: string }
> = {
  pending: { srLabel: "pending", labelClass: "text-muted-foreground" },
  running: { srLabel: "in progress", labelClass: "text-foreground" },
  done: { srLabel: "completed", labelClass: "text-muted-foreground" },
  failed: { srLabel: "failed", labelClass: "text-foreground" },
};

/** Per-step status indicator, sized to align with the first line of the label. */
function PlanStepIcon({ status }: { status: CopilotPlanStepStatus }) {
  const slot = "mt-0.5 flex size-4 shrink-0 items-center justify-center";
  switch (status) {
    case "done":
      return (
        <span
          className={cn(
            slot,
            "rounded-full bg-success text-success-foreground",
          )}
          aria-hidden="true"
        >
          <Check className="size-2.5" />
        </span>
      );
    case "running":
      return (
        <span className={slot} aria-hidden="true">
          <TypingDots size="sm" />
        </span>
      );
    case "failed":
      return (
        <span className={cn(slot, "text-destructive-text")} aria-hidden="true">
          <CircleAlert className="size-4" />
        </span>
      );
    default:
      return (
        <span
          className={cn(slot, "text-muted-foreground/40")}
          aria-hidden="true"
        >
          <Circle className="size-4" />
        </span>
      );
  }
}

export function CopilotPlanCard({
  title,
  description,
  steps,
  status = "idle",
  onExecute,
  onCancel,
  executeLabel = "Execute Plan",
  runningLabel = "Executing…",
  retryLabel = "Retry Plan",
  cancelLabel = "Stop",
  className,
}: CopilotPlanCardProps) {
  const badge = status === "idle" ? null : PLAN_BADGE[status];
  const isRunning = status === "running";
  const showStop = isRunning && !!onCancel;
  const hasFooter = status !== "done" && (!!onExecute || showStop);

  return (
    <Card className={cn("gap-3 py-3", className)}>
      <CardHeader className="px-3">
        <CardTitle>{title}</CardTitle>
        {description && (
          <CardDescription className="col-start-1">
            {description}
          </CardDescription>
        )}
        {badge && (
          <CardAction>
            <Badge variant={badge.variant} className="gap-1">
              {isRunning && <Spinner size="sm" />}
              {badge.label}
            </Badge>
          </CardAction>
        )}
      </CardHeader>

      <CardContent className="px-3">
        <ol className="flex flex-col border bg-muted/40">
          {steps.map((step, i) => {
            const stepStatus = step.status ?? "pending";
            return (
              <li
                key={i}
                className={cn(
                  "flex items-start gap-2.5 px-2.5 py-2",
                  i > 0 && "border-t",
                )}
              >
                <PlanStepIcon status={stepStatus} />
                <div className="flex min-w-0 flex-col gap-0.5">
                  <span
                    className={cn(
                      "text-body-small leading-snug",
                      STEP_STATUS[stepStatus].labelClass,
                    )}
                  >
                    {step.label}
                  </span>
                  {step.description && (
                    <span className="text-caption text-muted-foreground">
                      {step.description}
                    </span>
                  )}
                </div>
                <span className="sr-only">
                  {STEP_STATUS[stepStatus].srLabel}
                </span>
              </li>
            );
          })}
        </ol>
      </CardContent>

      {hasFooter && (
        <CardFooter className="px-3">
          {status === "failed" && onExecute ? (
            <Button
              type="button"
              variant="outline"
              size="sm"
              onClick={onExecute}
              className="h-8 w-full gap-1.5"
            >
              <RefreshCw className="size-3.5" aria-hidden="true" />
              {retryLabel}
            </Button>
          ) : showStop ? (
            <Button
              type="button"
              variant="outline"
              size="sm"
              onClick={onCancel}
              className="h-8 w-full gap-1.5 text-destructive-text"
            >
              <Square className="size-3.5 fill-current" aria-hidden="true" />
              {cancelLabel}
            </Button>
          ) : onExecute ? (
            <Button
              type="button"
              size="sm"
              onClick={onExecute}
              disabled={isRunning}
              className="h-8 w-full gap-1.5"
            >
              {isRunning ? (
                <Spinner size="sm" />
              ) : (
                <Play className="size-3.5" aria-hidden="true" />
              )}
              {isRunning ? runningLabel : executeLabel}
            </Button>
          ) : null}
        </CardFooter>
      )}
    </Card>
  );
}
