'use client';

import * as React from 'react';
import { cn } from '../../lib/utils';
import { StatusBadge } from '../badge/StatusBadge';
import { EmptyState } from '../states/EmptyState';
import type { NodeExecView } from './types';
import { NODE_STATUS_BADGE, formatDuration, isLiveStatus } from './exec-status';

export interface ExecutionTimelineProps {
  /** Per-node execution overlays; rendered sorted by `executionOrder`. */
  nodeExecutions: NodeExecView[];
  /** Currently selected node id (row highlighted as active). */
  activeNodeId?: string;
  /** Called with a node id when its row is activated. */
  onSelectNode?: (nodeId: string) => void;
  className?: string;
}

function byExecutionOrder(a: NodeExecView, b: NodeExecView): number {
  const ao = a.executionOrder ?? 0;
  const bo = b.executionOrder ?? 0;
  return ao - bo;
}

/**
 * Vertical execution timeline: one row per node execution (ordered by
 * `executionOrder`), each showing the node name, a status badge, the run
 * duration, and inline error text for failed nodes. Running nodes show a
 * pulsing live indicator; terminal nodes render statically.
 *
 * Read-only and app-agnostic — selection is surfaced via `onSelectNode`.
 */
export function ExecutionTimeline({
  nodeExecutions,
  activeNodeId,
  onSelectNode,
  className,
}: ExecutionTimelineProps) {
  const ordered = React.useMemo(
    () => [...nodeExecutions].sort(byExecutionOrder),
    [nodeExecutions]
  );

  if (ordered.length === 0) {
    return (
      <EmptyState
        title="No node executions"
        description="This run has not produced any node activity yet."
        className={className}
      />
    );
  }

  return (
    <ol className={cn('flex flex-col', className)} aria-label="Execution timeline">
      {ordered.map((node) => {
        const live = isLiveStatus(node.status);
        const isActive = activeNodeId != null && node.nodeId === activeNodeId;
        const duration = formatDuration(node.executionTimeMs);
        const selectable = onSelectNode != null;

        return (
          <li
            key={node.nodeId}
            aria-current={isActive ? 'true' : undefined}
            data-node-id={node.nodeId}
            data-status={node.status}
            className={cn(
              'group flex items-start gap-3 border-b border-border px-3 py-2.5 text-sm last:border-b-0',
              selectable && 'cursor-pointer hover:bg-accent/50',
              isActive && 'bg-accent'
            )}
            onClick={selectable ? () => onSelectNode!(node.nodeId) : undefined}
            onKeyDown={
              selectable
                ? (e) => {
                    if (e.key === 'Enter' || e.key === ' ') {
                      e.preventDefault();
                      onSelectNode!(node.nodeId);
                    }
                  }
                : undefined
            }
            tabIndex={selectable ? 0 : undefined}
          >
            {/* Status rail dot */}
            <span className="relative mt-1 flex h-2.5 w-2.5 shrink-0 items-center justify-center">
              {live ? (
                <>
                  <span
                    data-live="true"
                    aria-hidden="true"
                    className="absolute inline-flex h-full w-full animate-ping rounded-full bg-blue-400 opacity-75"
                  />
                  <span className="relative inline-flex h-2.5 w-2.5 rounded-full bg-blue-500" />
                </>
              ) : (
                <span
                  className={cn(
                    'inline-flex h-2.5 w-2.5 rounded-full',
                    node.status === 'success' && 'bg-green-500',
                    node.status === 'error' && 'bg-red-500',
                    node.status === 'skipped' && 'bg-gray-300',
                    node.status === 'pending' && 'bg-amber-400',
                    node.status === 'idle' && 'bg-gray-300'
                  )}
                />
              )}
            </span>

            <div className="min-w-0 flex-1">
              <div className="flex items-center gap-2">
                <span className="truncate font-medium text-foreground">
                  {node.name ?? node.nodeId}
                </span>
                {duration && (
                  <span className="ml-auto shrink-0 tabular-nums text-xs text-muted-foreground">
                    {duration}
                  </span>
                )}
              </div>
              <div className="mt-1 flex items-center gap-2">
                <StatusBadge
                  status={node.status}
                  config={NODE_STATUS_BADGE}
                  size="sm"
                />
                {node.type && (
                  <span className="truncate text-xs text-muted-foreground">
                    {node.type}
                  </span>
                )}
              </div>
              {node.status === 'error' && node.error && (
                <p className="mt-1.5 break-words text-xs text-red-600">
                  {node.error}
                </p>
              )}
            </div>
          </li>
        );
      })}
    </ol>
  );
}
