import { Container, SelectList, Spacer, Text } from '../../../tui/index.js';
import { theme } from '../../theme/runtime.js';
import { getSelectListTheme } from '../../theme/theme.js';
import { DynamicBorder } from '../primitives/dynamic-border.js';
/** Format a task's elapsed runtime as `Xs` or `Xm Ys`. */
function formatElapsed(task) {
    const end = task.completedAt ?? Date.now();
    const seconds = Math.max(0, Math.round((end - task.startedAt) / 1000));
    if (seconds < 60)
        return `${seconds}s`;
    return `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
}
/** Return 'background' or 'foreground' based on the task's launch mode. */
function taskMode(task) {
    return task.isBackgrounded ? 'background' : 'foreground';
}
/** Build the colored status-dot + name label for a task list row. */
function taskLabel(task) {
    return `${statusDot(task)} ${task.name || task.agentId}`;
}
/** Build the single-line summary description shown beneath a task label. */
function taskDescription(task) {
    return stripForList(`${task.subagentType} | ${task.status}/${taskMode(task)} | ${toolSummary(task)} | ${usageSummary(task)} | ${formatElapsed(task)}`);
}
/** Convert tasks to SelectList items keyed by agentId. */
function toItems(tasks) {
    return tasks.map((task) => ({
        value: task.agentId,
        label: taskLabel(task),
        description: taskDescription(task)
    }));
}
/** Truncate a string to max length, appending ellipsis when shortened. */
function truncate(value, max) {
    return value.length <= max ? value : `${value.slice(0, Math.max(0, max - 3))}...`;
}
/** Collapse whitespace so a value renders cleanly on a single list row. */
function stripForList(value) {
    return value.replace(/\s+/g, ' ').trim();
}
/** Themed status dot indicator for a task's lifecycle state. */
function statusDot(task) {
    if (task.status === 'completed')
        return theme.fg('success', '●');
    if (task.status === 'failed')
        return theme.fg('error', '●');
    if (task.status === 'killed')
        return theme.fg('warning', '●');
    return theme.fg('accent', '●');
}
/** Themed `status/mode` text colored by lifecycle state. */
function statusText(task) {
    const text = `${task.status}/${taskMode(task)}`;
    if (task.status === 'completed')
        return theme.fg('success', text);
    if (task.status === 'failed')
        return theme.fg('error', text);
    if (task.status === 'killed')
        return theme.fg('warning', text);
    return theme.fg('accent', text);
}
/** Compact `total tok (in/out)` token usage summary for a task. */
function usageSummary(task) {
    if (!task.usage)
        return 'usage pending';
    const total = task.usage.input + task.usage.output;
    return `${formatCompactCount(total)} tok (${formatCompactCount(task.usage.input)} in/${formatCompactCount(task.usage.output)} out)`;
}
/** Format an integer count using compact `k`/`M` suffixes. */
function formatCompactCount(count) {
    if (count < 1_000)
        return count.toString();
    if (count < 9_950)
        return `${(count / 1_000).toFixed(1)}k`;
    if (count < 1_000_000)
        return `${Math.round(count / 1_000)}k`;
    return `${(count / 1_000_000).toFixed(1)}M`;
}
/** Summarize a task's total tool calls plus any in-flight pending count. */
function toolSummary(task) {
    const pending = task.activeToolUses > 0 ? `, ${task.activeToolUses} pending` : '';
    return `${task.toolUses} tools${pending}`;
}
/** Parse a `tool start ...` activity line into a tool block, or undefined if not a match. */
function parseToolStart(line) {
    const match = /^tool start (\S+) (\S+)(?: (.*))?$/.exec(line);
    if (!match)
        return undefined;
    const [, first, second, rest] = match;
    if (second?.startsWith('{')) {
        return { kind: 'tool', name: first ?? 'tool', args: rest ? `${second} ${rest}` : second };
    }
    return { kind: 'tool', id: first, name: second ?? 'tool', args: rest };
}
/** Parse a `tool done|error ...` activity line into a structured end record. */
function parseToolEnd(line) {
    const match = /^tool (done|error) (\S+)(?: (\S+))?(?:: (.*))?$/.exec(line);
    if (!match)
        return undefined;
    const [, status, first, second, result] = match;
    if (!second) {
        return { status: status, name: first ?? 'tool', result };
    }
    return { status: status, id: first, name: second, result };
}
/** Reconstruct the most recent tool/output activity blocks from a task's output stream. */
function buildActivityBlocks(task) {
    const source = task.outputLines.length > 0 ? task.outputLines : task.errorMessage ? [task.errorMessage] : [];
    const blocks = [];
    const openById = new Map();
    const openByName = new Map();
    const rememberOpen = (block) => {
        if (block.id)
            openById.set(block.id, block);
        const list = openByName.get(block.name) ?? [];
        list.push(block);
        openByName.set(block.name, list);
    };
    const forgetOpen = (block) => {
        if (block.id)
            openById.delete(block.id);
        const list = openByName.get(block.name);
        if (!list)
            return;
        const index = list.indexOf(block);
        if (index >= 0)
            list.splice(index, 1);
        if (list.length === 0)
            openByName.delete(block.name);
    };
    for (const rawLine of source) {
        const line = rawLine.replace(/\s+/g, ' ').trim();
        if (!line)
            continue;
        const start = parseToolStart(line);
        if (start) {
            blocks.push(start);
            rememberOpen(start);
            continue;
        }
        const end = parseToolEnd(line);
        if (end) {
            const block = (end.id ? openById.get(end.id) : undefined) ?? openByName.get(end.name)?.[0];
            if (block) {
                block.result = end.result;
                block.isError = end.status === 'error';
                forgetOpen(block);
            }
            else {
                blocks.push({
                    kind: 'tool',
                    id: end.id,
                    name: end.name,
                    result: end.result,
                    isError: end.status === 'error'
                });
            }
            continue;
        }
        blocks.push({ kind: 'output', text: line });
    }
    if (blocks.length > 0)
        return blocks.slice(-12);
    return task.recentToolCalls.slice(-6).map((tool) => ({
        kind: 'tool',
        name: tool.name,
        args: stringifyArgs(tool.args)
    }));
}
/** JSON-stringify tool args, falling back to String() on failure. */
function stringifyArgs(args) {
    try {
        return JSON.stringify(args);
    }
    catch {
        return String(args);
    }
}
/** Render the recent activity section (tools + output) for a task detail view. */
function renderActivity(task) {
    const blocks = buildActivityBlocks(task);
    if (blocks.length === 0)
        return [theme.fg('dim', 'No activity yet')];
    let toolIndex = 0;
    const lines = [];
    for (const block of blocks) {
        if (block.kind === 'output') {
            lines.push(`  ${theme.fg('muted', `output ${truncate(block.text, 180)}`)}`);
            continue;
        }
        toolIndex++;
        const resultLabel = block.isError ? theme.fg('error', 'result') : theme.fg('dim', 'result');
        lines.push(`  ${theme.fg('accent', `#${toolIndex} ${block.name}`)}`);
        if (block.args)
            lines.push(`    ${theme.fg('dim', `call ${truncate(block.args, 160)}`)}`);
        lines.push(`    ${resultLabel} ${block.result
            ? theme.fg(block.isError ? 'error' : 'muted', truncate(block.result, 180))
            : theme.fg('dim', 'pending')}`);
    }
    return lines;
}
/** Render the multi-line detail view for an inspected task. */
export function renderDetail(task) {
    const prompt = truncate(task.prompt.replace(/\s+/g, ' ').trim(), 420) || '(empty)';
    return [
        `${statusDot(task)} ${theme.bold(theme.fg('accent', task.name || task.agentId))} ${theme.fg('dim', task.agentId)}`,
        [
            `${theme.fg('dim', 'state')} ${statusText(task)}`,
            `${theme.fg('dim', 'type')} ${task.subagentType}`,
            `${theme.fg('dim', 'elapsed')} ${formatElapsed(task)}`,
            `${theme.fg('dim', 'tools')} ${toolSummary(task)}`,
            `${theme.fg('dim', 'usage')} ${usageSummary(task)}`,
            task.pendingMessages.length > 0
                ? `${theme.fg('dim', 'queued')} ${task.pendingMessages.length}`
                : undefined
        ]
            .filter((part) => part !== undefined)
            .join('  '),
        '',
        theme.fg('muted', 'Prompt'),
        `  ${theme.fg('muted', prompt)}`,
        '',
        theme.fg('muted', 'Activity'),
        ...renderActivity(task),
        '',
        theme.fg('dim', 'esc back  k kill running task')
    ]
        .filter((line) => line !== undefined)
        .join('\n');
}
export class AgentTasksSelectorComponent extends Container {
    scopeId;
    taskManager;
    callbacks;
    list;
    selectedAgentId;
    detailAgentId;
    unsubscribe;
    /** Build the agent-tasks selector and subscribe to TaskManager updates. */
    constructor(scopeId, taskManager, callbacks) {
        super();
        this.scopeId = scopeId;
        this.taskManager = taskManager;
        this.callbacks = callbacks;
        this.list = this.createList();
        this.unsubscribe = taskManager.subscribe(() => {
            this.refresh();
            this.callbacks.requestRender();
        });
        this.renderContent();
    }
    /** Unsubscribe from TaskManager updates. */
    dispose() {
        this.unsubscribe();
    }
    /** Live list of tasks for the current scope. */
    get tasks() {
        return this.taskManager.list(this.scopeId);
    }
    /** Construct the SelectList component wired to selection/cancel callbacks. */
    createList() {
        const list = new SelectList(toItems(this.tasks), 8, getSelectListTheme());
        list.onSelect = (item) => {
            this.detailAgentId = item.value;
            this.renderContent();
            this.callbacks.requestRender();
        };
        list.onSelectionChange = (item) => {
            this.selectedAgentId = item.value;
        };
        list.onCancel = () => this.callbacks.onCancel();
        if (this.selectedAgentId) {
            const index = this.tasks.findIndex((task) => task.agentId === this.selectedAgentId);
            if (index >= 0)
                list.setSelectedIndex(index);
        }
        return list;
    }
    /** Rebuild the list and detail view in response to TaskManager changes. */
    refresh() {
        if (this.detailAgentId && !this.taskManager.get(this.scopeId, this.detailAgentId)) {
            this.detailAgentId = undefined;
        }
        this.list = this.createList();
        this.renderContent();
    }
    /** Re-render the selector body, switching between list and detail views. */
    renderContent() {
        this.clear();
        this.addChild(new DynamicBorder());
        this.addChild(new Text(theme.bold(theme.fg('accent', 'Agents')), 0, 0));
        this.addChild(new Spacer(1));
        const detailTask = this.detailAgentId && this.taskManager.get(this.scopeId, this.detailAgentId);
        if (detailTask && detailTask !== 'ambiguous') {
            this.addChild(new Text(renderDetail(detailTask), 0, 0));
            this.addChild(new DynamicBorder());
            return;
        }
        if (this.tasks.length === 0) {
            this.addChild(new Text(theme.fg('dim', 'No agents for this session.'), 0, 0));
            this.addChild(new Text(theme.fg('dim', 'esc close'), 0, 0));
            this.addChild(new DynamicBorder());
            return;
        }
        this.addChild(new Text(theme.fg('dim', 'up/down select  enter inspect  esc close'), 0, 0));
        this.addChild(new Spacer(1));
        this.addChild(this.list);
        this.addChild(new DynamicBorder());
    }
    /** Route input to the detail view (kill/escape) or back to the list. */
    handleInput(data) {
        if (this.detailAgentId) {
            if (data === 'k') {
                const task = this.taskManager.get(this.scopeId, this.detailAgentId);
                if (task && task !== 'ambiguous' && task.status === 'running') {
                    this.callbacks.onKill(task.agentId);
                }
                return;
            }
            this.detailAgentId = undefined;
            this.renderContent();
            this.callbacks.requestRender();
            return;
        }
        this.list.handleInput(data);
    }
}
//# sourceMappingURL=agent-tasks-selector.js.map