import type { CSSProperties, ReactNode } from 'react';
import { ToolCallCard } from './ToolCallCard.js';
import type { ToolInvocation } from './types.js';

export type AgentStepKind =
  | 'thought'
  | 'tool_call'
  | 'observation'
  | 'response'
  | 'custom';

export interface AgentStep {
  id: string;
  kind: AgentStepKind;
  /** Step body. For 'tool_call' supply a ToolInvocation, else freeform. */
  content?: ReactNode;
  /** Required when kind === 'tool_call'. */
  invocation?: ToolInvocation;
  /** Override the label rendered in the marker column. */
  label?: string;
  /** Visually mark this step as still in-progress (e.g. streaming). */
  isActive?: boolean;
}

export interface AgentTimelineProps {
  steps: AgentStep[];
  className?: string;
  style?: CSSProperties;
}

/**
 * `<AgentTimeline>` — vertical trace of agent steps in the
 * `think → act → observe → respond` loop. Used by JarvisJr and any
 * agentic flow that wants to expose the agent's reasoning chain.
 *
 * Each step renders with a colored marker dot, a kind label, and a
 * body slot. `kind === 'tool_call'` automatically uses `<ToolCallCard>`
 * so the rendering stays consistent across the catalog.
 */
export function AgentTimeline({ steps, className, style }: AgentTimelineProps) {
  return (
    <ol
      data-testid="bl-agent-timeline"
      className={className}
      style={{
        listStyle: 'none',
        margin: 0,
        padding: 0,
        display: 'flex',
        flexDirection: 'column',
        gap: 0,
        position: 'relative',
        ...style,
      }}
    >
      {steps.map((step, idx) => (
        <Step key={step.id} step={step} isLast={idx === steps.length - 1} />
      ))}
    </ol>
  );
}

function Step({ step, isLast }: { step: AgentStep; isLast: boolean }) {
  const palette = STEP_PALETTE[step.kind];
  return (
    <li
      data-testid={`bl-agent-step-${step.id}`}
      data-kind={step.kind}
      style={{
        position: 'relative',
        display: 'grid',
        gridTemplateColumns: '32px 1fr',
        gap: 'var(--bl-space-3, 12px)',
        paddingBottom: isLast ? 0 : 'var(--bl-space-4, 16px)',
      }}
    >
      {/* Marker rail */}
      <div
        style={{
          position: 'relative',
          display: 'flex',
          justifyContent: 'center',
          paddingTop: 4,
        }}
      >
        <span
          aria-hidden
          style={{
            display: 'inline-block',
            width: 12,
            height: 12,
            borderRadius: '50%',
            background: palette.dot,
            boxShadow: step.isActive
              ? `0 0 0 4px ${palette.glow}`
              : `0 0 0 2px var(--bl-surface-card, #fff)`,
            transition: 'box-shadow 200ms ease',
          }}
        />
        {!isLast && (
          <span
            aria-hidden
            style={{
              position: 'absolute',
              top: 18,
              bottom: -12,
              width: 2,
              background: 'var(--bl-border, rgba(0,0,0,0.1))',
            }}
          />
        )}
      </div>

      {/* Body */}
      <div style={{ minWidth: 0 }}>
        <div
          style={{
            fontSize: '0.7rem',
            fontWeight: 700,
            textTransform: 'uppercase',
            letterSpacing: '0.06em',
            color: palette.label,
            marginBottom: 'var(--bl-space-1, 4px)',
          }}
        >
          {step.label ?? STEP_LABELS[step.kind]}
        </div>
        {step.kind === 'tool_call' && step.invocation ? (
          <ToolCallCard invocation={step.invocation} defaultExpanded={step.isActive} />
        ) : (
          <div
            style={{
              fontSize: '0.9rem',
              lineHeight: 1.5,
              color: 'var(--bl-text-primary, inherit)',
              whiteSpace: 'pre-wrap',
              wordBreak: 'break-word',
            }}
          >
            {step.content}
          </div>
        )}
      </div>
    </li>
  );
}

const STEP_LABELS: Record<AgentStepKind, string> = {
  thought: 'Thought',
  tool_call: 'Action',
  observation: 'Observation',
  response: 'Response',
  custom: 'Step',
};

const STEP_PALETTE: Record<AgentStepKind, { dot: string; glow: string; label: string }> = {
  thought: {
    dot: 'var(--bl-text-tertiary, #888)',
    glow: 'var(--bl-surface-muted, rgba(0,0,0,0.04))',
    label: 'var(--bl-text-tertiary, #888)',
  },
  tool_call: {
    dot: 'var(--bl-accent, #6366f1)',
    glow: 'var(--bl-accent-muted, rgba(99,102,241,0.18))',
    label: 'var(--bl-accent, #6366f1)',
  },
  observation: {
    dot: 'var(--bl-info, #38bdf8)',
    glow: 'var(--bl-info-muted, rgba(56,189,248,0.18))',
    label: 'var(--bl-info, #38bdf8)',
  },
  response: {
    dot: 'var(--bl-success, #22c55e)',
    glow: 'var(--bl-success-muted, rgba(34,197,94,0.18))',
    label: 'var(--bl-success, #22c55e)',
  },
  custom: {
    dot: 'var(--bl-text-secondary, #555)',
    glow: 'var(--bl-surface-muted, rgba(0,0,0,0.06))',
    label: 'var(--bl-text-secondary, #555)',
  },
};
