import { stringify as stringifyYaml } from 'yaml';
import { WorkflowRunner } from './runner.js';
import { formatDryRunReport } from './dry-run-format.js';
// ── WorkflowBuilder ─────────────────────────────────────────────────────────
/**
 * Fluent builder for constructing workflow configurations programmatically.
 *
 * @example
 * ```typescript
 * import { workflow } from "@agent-relay/sdk/workflows";
 *
 * const result = await workflow("my-workflow")
 *   .pattern("dag")
 *   .agent("worker", { cli: "claude", role: "Backend engineer" })
 *   .step("build", { agent: "worker", task: "Build the project" })
 *   .step("test", { agent: "worker", task: "Run tests", dependsOn: ["build"] })
 *   .run();
 * ```
 */
export class WorkflowBuilder {
    _name;
    _description;
    _pattern = 'dag';
    _maxConcurrency;
    _timeoutMs;
    _channel;
    _idleNudge;
    _agents = [];
    _steps = [];
    _errorHandling;
    constructor(name) {
        this._name = name;
    }
    /** Set workflow description. */
    description(desc) {
        this._description = desc;
        return this;
    }
    /** Set swarm pattern (default: "dag"). */
    pattern(p) {
        this._pattern = p;
        return this;
    }
    /** Set maximum concurrent agents. */
    maxConcurrency(n) {
        this._maxConcurrency = n;
        return this;
    }
    /** Set global timeout in milliseconds. */
    timeout(ms) {
        this._timeoutMs = ms;
        return this;
    }
    /** Set the relay channel for agent communication. */
    channel(ch) {
        this._channel = ch;
        return this;
    }
    /** Configure idle agent detection and nudging for interactive agents. */
    idleNudge(config) {
        this._idleNudge = config;
        return this;
    }
    /** Add an agent definition. */
    agent(name, options) {
        const def = {
            name,
            cli: options.cli,
        };
        if (options.role !== undefined)
            def.role = options.role;
        if (options.task !== undefined)
            def.task = options.task;
        if (options.channels !== undefined)
            def.channels = options.channels;
        if (options.interactive !== undefined)
            def.interactive = options.interactive;
        if (options.model !== undefined ||
            options.maxTokens !== undefined ||
            options.timeoutMs !== undefined ||
            options.retries !== undefined ||
            options.idleThresholdSecs !== undefined) {
            def.constraints = {};
            if (options.model !== undefined)
                def.constraints.model = options.model;
            if (options.maxTokens !== undefined)
                def.constraints.maxTokens = options.maxTokens;
            if (options.timeoutMs !== undefined)
                def.constraints.timeoutMs = options.timeoutMs;
            if (options.retries !== undefined)
                def.constraints.retries = options.retries;
            if (options.idleThresholdSecs !== undefined)
                def.constraints.idleThresholdSecs = options.idleThresholdSecs;
        }
        this._agents.push(def);
        return this;
    }
    /** Add a workflow step. */
    step(name, options) {
        const step = {
            name,
            agent: options.agent,
            task: options.task,
        };
        if (options.dependsOn !== undefined)
            step.dependsOn = options.dependsOn;
        if (options.verification !== undefined)
            step.verification = options.verification;
        if (options.timeoutMs !== undefined)
            step.timeoutMs = options.timeoutMs;
        if (options.retries !== undefined)
            step.retries = options.retries;
        this._steps.push(step);
        return this;
    }
    /** Set error handling strategy. */
    onError(strategy, options) {
        this._errorHandling = { strategy };
        if (options?.maxRetries !== undefined)
            this._errorHandling.maxRetries = options.maxRetries;
        if (options?.retryDelayMs !== undefined)
            this._errorHandling.retryDelayMs = options.retryDelayMs;
        if (options?.notifyChannel !== undefined)
            this._errorHandling.notifyChannel = options.notifyChannel;
        return this;
    }
    /** Build and return the RelayYamlConfig object. */
    toConfig() {
        if (this._agents.length === 0) {
            throw new Error('Workflow must have at least one agent');
        }
        if (this._steps.length === 0) {
            throw new Error('Workflow must have at least one step');
        }
        const wfDef = {
            name: `${this._name}-workflow`,
            steps: [...this._steps],
        };
        const config = {
            version: '1.0',
            name: this._name,
            swarm: {
                pattern: this._pattern,
            },
            agents: [...this._agents],
            workflows: [wfDef],
        };
        if (this._description !== undefined)
            config.description = this._description;
        if (this._maxConcurrency !== undefined)
            config.swarm.maxConcurrency = this._maxConcurrency;
        if (this._timeoutMs !== undefined)
            config.swarm.timeoutMs = this._timeoutMs;
        if (this._channel !== undefined)
            config.swarm.channel = this._channel;
        if (this._idleNudge !== undefined)
            config.swarm.idleNudge = this._idleNudge;
        if (this._errorHandling !== undefined)
            config.errorHandling = this._errorHandling;
        return config;
    }
    /** Serialize the config to a YAML string. */
    toYaml() {
        return stringifyYaml(this.toConfig());
    }
    async run(options = {}) {
        const config = this.toConfig();
        const runner = new WorkflowRunner({
            cwd: options.cwd,
            relay: options.relay,
        });
        // Auto-detect DRY_RUN env var so existing scripts get dry-run for free
        const isDryRun = options.dryRun ?? !!process.env.DRY_RUN;
        if (isDryRun) {
            const report = runner.dryRun(config, options.workflow, options.vars);
            console.log(formatDryRunReport(report));
            return report;
        }
        if (options.onEvent) {
            runner.on(options.onEvent);
        }
        return runner.execute(config, options.workflow, options.vars);
    }
}
// ── Entry point ─────────────────────────────────────────────────────────────
/**
 * Create a new workflow builder.
 *
 * @example
 * ```typescript
 * const result = await workflow("my-task")
 *   .pattern("fan-out")
 *   .agent("worker", { cli: "claude" })
 *   .step("do-work", { agent: "worker", task: "Build the feature" })
 *   .run();
 * ```
 */
export function workflow(name) {
    return new WorkflowBuilder(name);
}
//# sourceMappingURL=builder.js.map