import { OrchestrationTaskStore } from '../../../modules/orchestration/tasks/orchestration-task-store.js';
import { a2aBus } from '../../../modules/orchestration/a2a/bus.js';
function newId(prefix) {
    return `${prefix}_${Math.random().toString(36).slice(2, 10)}`;
}
const TERMINAL_A2A_STATES = ['completed', 'canceled', 'failed'];
class OrchestrationTaskService {
    store;
    constructor(store) {
        this.store = store ?? new OrchestrationTaskStore();
        this.watchA2ATerminalStates();
    }
    list(projectId) {
        return this.store.list(projectId);
    }
    get(id) {
        return this.store.get(id);
    }
    create(input) {
        const now = Date.now();
        const task = {
            id: newId('otask'),
            projectId: input.projectId,
            title: input.title,
            description: input.description,
            taskmasterId: input.taskmasterId,
            state: 'todo',
            createdAt: now,
            updatedAt: now,
        };
        this.store.set(task);
        return task;
    }
    upsertFromTaskMaster(input) {
        const existing = this.store.list(input.projectId).find((task) => task.taskmasterId === input.taskmasterId);
        if (existing) {
            existing.title = input.title;
            existing.description = input.description;
            existing.updatedAt = Date.now();
            this.store.set(existing);
            return existing;
        }
        return this.create(input);
    }
    async dispatch(taskId, input) {
        const task = this.store.get(taskId);
        if (!task)
            throw new Error('TASK_NOT_FOUND');
        const a2aResponse = await fetch(`http://127.0.0.1:${process.env.SERVER_PORT ?? '3001'}/a2a/tasks`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                adapterId: input.adapterId,
                message: {
                    messageId: newId('msg'),
                    role: 'user',
                    parts: [{ kind: 'text', text: `${task.title}\n\n${task.description ?? ''}` }],
                },
                metadata: {
                    isolation: input.isolation ?? 'worktree',
                    orchestrationTaskId: task.id,
                    taskmasterId: task.taskmasterId,
                },
            }),
        });
        const body = await a2aResponse.json().catch(() => null);
        if (!a2aResponse.ok || typeof body?.id !== 'string') {
            throw new Error(body?.error?.message ?? 'DISPATCH_FAILED');
        }
        task.a2aTaskId = body.id;
        task.adapterId = input.adapterId;
        task.adapterSelector = input.adapterId;
        task.workspaceKind = input.isolation ?? 'worktree';
        task.state = 'in_progress';
        task.updatedAt = Date.now();
        this.store.set(task);
        return task;
    }
    updateState(taskId, state) {
        const task = this.store.get(taskId);
        if (!task)
            return undefined;
        task.state = state;
        task.updatedAt = Date.now();
        this.store.set(task);
        return task;
    }
    watchA2ATerminalStates() {
        a2aBus.subscribeAll((event) => {
            if (event.kind !== 'task-state')
                return;
            if (!TERMINAL_A2A_STATES.includes(event.state))
                return;
            const orchTask = this.store.getByA2ATaskId(event.taskId);
            if (!orchTask)
                return;
            if (orchTask.state === 'done' || orchTask.state === 'failed' || orchTask.state === 'canceled')
                return;
            const mapped = event.state === 'completed' ? 'done'
                : event.state === 'failed' ? 'failed'
                    : 'canceled';
            orchTask.state = mapped;
            orchTask.updatedAt = Date.now();
            this.store.set(orchTask);
            if (orchTask.taskmasterId && mapped === 'done') {
                this.syncTaskMasterStatus(orchTask.taskmasterId, 'done');
            }
        });
    }
    syncTaskMasterStatus(taskmasterId, status) {
        const { spawn } = require('node:child_process');
        spawn('task-master', ['set-status', '--id', taskmasterId, '--status', status], {
            stdio: 'ignore',
            detached: true,
        }).unref();
    }
    cancel(taskId) {
        const task = this.store.get(taskId);
        if (!task)
            throw new Error('TASK_NOT_FOUND');
        task.state = 'canceled';
        task.updatedAt = Date.now();
        this.store.set(task);
        return task;
    }
}
export const orchestrationTaskService = new OrchestrationTaskService();
//# sourceMappingURL=orchestration-task.service.js.map