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

export interface ToolCallCardProps {
  invocation: ToolInvocation;
  /** Initially expanded? Default: false. */
  defaultExpanded?: boolean;
  /** Override the title rendered to the right of the status pill. */
  title?: ReactNode;
  /** Render a custom output preview (overrides default JSON pretty-print). */
  renderOutput?: (output: unknown) => ReactNode;
  className?: string;
  style?: CSSProperties;
}

/**
 * Disclosure card showing a single LLM tool call. Collapsed by default,
 * expands to show the input + output JSON. Status pill + name are always
 * visible.
 *
 * Visual states:
 *   pending   — gray pill, dotted spinner
 *   streaming — accent pill, animated dots
 *   success   — success-token pill, ✓
 *   error     — danger-token pill, ✕ + error string in body
 */
export function ToolCallCard({
  invocation,
  defaultExpanded = false,
  title,
  renderOutput,
  className,
  style,
}: ToolCallCardProps) {
  const [open, setOpen] = useState(defaultExpanded);
  const { name, status, input, output, error, durationMs } = invocation;

  return (
    <article
      data-testid={`bl-tool-call-${invocation.id}`}
      data-status={status}
      className={className}
      style={{
        border: '1px solid var(--bl-border, rgba(0,0,0,0.08))',
        borderRadius: 'var(--bl-radius-card, 10px)',
        background: 'var(--bl-surface-card, #fff)',
        overflow: 'hidden',
        fontSize: '0.85rem',
        ...style,
      }}
    >
      <button
        type="button"
        data-testid="bl-tool-call-toggle"
        onClick={() => setOpen(o => !o)}
        aria-expanded={open}
        style={{
          width: '100%',
          display: 'flex',
          alignItems: 'center',
          gap: 'var(--bl-space-2, 8px)',
          padding: 'var(--bl-space-2, 8px) var(--bl-space-3, 12px)',
          background: 'transparent',
          border: 'none',
          textAlign: 'left',
          cursor: 'pointer',
          color: 'inherit',
        }}
      >
        <StatusPill status={status} />
        <span style={{ fontFamily: 'var(--bl-font-mono, ui-monospace)', fontWeight: 600 }}>
          {title ?? name}
        </span>
        {typeof durationMs === 'number' && (
          <span
            style={{
              marginLeft: 'auto',
              fontSize: '0.75rem',
              color: 'var(--bl-text-tertiary, #888)',
            }}
          >
            {durationMs}ms
          </span>
        )}
        <span
          aria-hidden
          style={{
            transition: 'transform 120ms ease',
            transform: open ? 'rotate(90deg)' : 'rotate(0deg)',
            color: 'var(--bl-text-tertiary, #888)',
          }}
        >
          ▸
        </span>
      </button>

      {open && (
        <div
          data-testid="bl-tool-call-body"
          style={{
            borderTop: '1px solid var(--bl-border-subtle, rgba(0,0,0,0.06))',
            padding: 'var(--bl-space-3, 12px)',
            display: 'flex',
            flexDirection: 'column',
            gap: 'var(--bl-space-2, 8px)',
            fontFamily: 'var(--bl-font-mono, ui-monospace, monospace)',
            fontSize: '0.78rem',
            background: 'var(--bl-surface-muted, #fafafa)',
          }}
        >
          {input !== undefined && (
            <Section label="input">
              <Pre>{stringifyShort(input)}</Pre>
            </Section>
          )}
          {status === 'error' ? (
            <Section label="error" tone="danger">
              <Pre>{error ?? 'Tool call failed.'}</Pre>
            </Section>
          ) : output !== undefined ? (
            <Section label="output">
              {renderOutput ? renderOutput(output) : <Pre>{stringifyShort(output)}</Pre>}
            </Section>
          ) : null}
        </div>
      )}
    </article>
  );
}

function StatusPill({ status }: { status: ToolCallStatus }) {
  const map: Record<ToolCallStatus, { bg: string; fg: string; label: string }> = {
    pending: {
      bg: 'var(--bl-surface-muted, rgba(0,0,0,0.04))',
      fg: 'var(--bl-text-tertiary, #888)',
      label: '…',
    },
    streaming: {
      bg: 'var(--bl-accent-muted, rgba(99,102,241,0.12))',
      fg: 'var(--bl-accent, #6366f1)',
      label: '⋯',
    },
    success: {
      bg: 'var(--bl-success-muted, rgba(34,197,94,0.12))',
      fg: 'var(--bl-success, #22c55e)',
      label: '✓',
    },
    error: {
      bg: 'var(--bl-danger-muted, rgba(239,68,68,0.12))',
      fg: 'var(--bl-danger, #ef4444)',
      label: '✕',
    },
  };
  const v = map[status];
  return (
    <span
      data-testid="bl-tool-call-status"
      aria-label={`Status: ${status}`}
      style={{
        display: 'inline-flex',
        alignItems: 'center',
        justifyContent: 'center',
        width: 22,
        height: 22,
        borderRadius: 'var(--bl-radius-pill, 999px)',
        background: v.bg,
        color: v.fg,
        fontSize: 12,
        fontWeight: 700,
        flexShrink: 0,
      }}
    >
      {v.label}
    </span>
  );
}

function Section({
  label,
  tone,
  children,
}: {
  label: string;
  tone?: 'danger';
  children: ReactNode;
}) {
  return (
    <div>
      <div
        style={{
          fontSize: '0.7rem',
          fontWeight: 700,
          textTransform: 'uppercase',
          letterSpacing: '0.06em',
          color:
            tone === 'danger'
              ? 'var(--bl-danger, #ef4444)'
              : 'var(--bl-text-tertiary, #888)',
          marginBottom: 'var(--bl-space-1, 4px)',
        }}
      >
        {label}
      </div>
      {children}
    </div>
  );
}

function Pre({ children }: { children: ReactNode }) {
  return (
    <pre
      style={{
        margin: 0,
        whiteSpace: 'pre-wrap',
        wordBreak: 'break-word',
        background: 'var(--bl-surface-card, #fff)',
        padding: 'var(--bl-space-2, 8px)',
        borderRadius: 'var(--bl-radius-control, 6px)',
        border: '1px solid var(--bl-border-subtle, rgba(0,0,0,0.06))',
      }}
    >
      {children}
    </pre>
  );
}

function stringifyShort(value: unknown): string {
  if (typeof value === 'string') return value;
  try {
    return JSON.stringify(value, null, 2);
  } catch {
    return String(value);
  }
}
