import { randomUUID } from "node:crypto";
import path from "node:path";
export class AgentWorkflowService {
    state;
    projectPath;
    scope;
    constructor(state, projectPath) {
        this.state = state;
        this.projectPath = projectPath;
        this.scope = `agent_workflows:${path.resolve(projectPath)}`;
    }
    start(input) {
        const now = Date.now();
        const id = `workflow_${randomUUID()}`;
        const roles = ensureReviewerRole(normalizeRoles(input.roles, input.objective), input.acceptanceCriteria ?? []);
        const record = {
            id,
            runId: input.runId,
            objective: input.objective,
            roles,
            acceptanceCriteria: input.acceptanceCriteria ?? [],
            maxSteps: Math.min(50, Math.max(1, Math.trunc(input.maxSteps ?? 12))),
            status: "running",
            createdAtMs: now,
            updatedAtMs: now,
        };
        this.save(record);
        this.setActiveWorkflowId(id);
        this.state.saveCheckpoint(input.runId, `agent_workflow:${id}:roles`, record);
        this.state.appendEvent(input.runId, "agent_workflow_started", {
            workflow_id: id,
            objective: input.objective,
            role_count: roles.length,
            roles: roles.map((role) => role.name),
        });
        for (const role of roles) {
            const taskId = this.state.createTask({
                runId: input.runId,
                agent: role.name,
                title: role.responsibility,
                detail: [
                    `workflow=${id}`,
                    role.skills.length ? `skills=${role.skills.join(",")}` : "",
                    role.tools.length ? `tools=${role.tools.join(",")}` : "",
                ].filter(Boolean).join(" "),
            });
            this.state.appendEvent(input.runId, "agent_workflow_role_task_created", {
                workflow_id: id,
                task_id: taskId,
                role,
            });
        }
        this.addMessage(id, {
            from: "supervisor",
            to: "all",
            message: `Workflow started: ${input.objective}`,
            createdAtMs: now,
        });
        return record;
    }
    message(input) {
        const record = this.resolve(input.workflowId);
        const entry = {
            from: input.from,
            to: input.to,
            message: input.message,
            createdAtMs: Date.now(),
        };
        this.addMessage(record.id, entry);
        this.state.appendEvent(input.runId, "agent_workflow_message", {
            workflow_id: record.id,
            ...entry,
        });
        return record;
    }
    finish(input) {
        const record = this.resolve(input.workflowId);
        const next = {
            ...record,
            status: input.status,
            updatedAtMs: Date.now(),
        };
        this.save(next);
        this.state.saveCheckpoint(input.runId, `agent_workflow:${next.id}:final`, {
            ...next,
            summary: input.summary,
            artifacts: input.artifacts ?? [],
            issues: input.issues ?? [],
        });
        this.state.appendEvent(input.runId, "agent_workflow_finished", {
            workflow_id: next.id,
            status: input.status,
            summary: input.summary,
            artifacts: input.artifacts ?? [],
            issues: input.issues ?? [],
        });
        if (input.status === "succeeded") {
            for (const task of this.state.listTasks(input.runId).filter((task) => task.detail.includes(`workflow=${next.id}`))) {
                if (task.status !== "succeeded") {
                    this.state.updateTaskStatus(task.id, "succeeded", "workflow finished");
                }
            }
        }
        return next;
    }
    status(workflowId) {
        const record = this.resolve(workflowId);
        return {
            record,
            tasks: this.state.listTasks(record.runId).filter((task) => task.detail.includes(`workflow=${record.id}`)),
            messages: this.messages(record.id),
        };
    }
    formatStatus(workflowId) {
        const { record, tasks, messages } = this.status(workflowId);
        const counts = {
            total: tasks.length,
            done: tasks.filter((task) => task.status === "succeeded").length,
            running: tasks.filter((task) => task.status === "running").length,
            pending: tasks.filter((task) => task.status === "queued" || task.status === "paused").length,
            failed: tasks.filter((task) => task.status === "failed").length,
        };
        return [
            `workflow=${record.id}`,
            `status=${record.status}`,
            `objective=${record.objective}`,
            `roles=${record.roles.map((role) => role.name).join(", ")}`,
            `tasks=${counts.done}/${counts.total} done, running=${counts.running}, pending=${counts.pending}, failed=${counts.failed}`,
            record.acceptanceCriteria.length ? `acceptance=${record.acceptanceCriteria.join(" | ")}` : "",
            messages.length ? `last_message=${messages.at(-1)?.from} -> ${messages.at(-1)?.to}: ${messages.at(-1)?.message}` : "",
        ].filter(Boolean).join("\n");
    }
    resolve(workflowId) {
        const id = workflowId?.trim() || this.activeWorkflowId();
        if (!id)
            throw new Error("No active agent workflow. Call start_agent_workflow first.");
        const record = this.state.getUiState(this.scope, id);
        if (!record)
            throw new Error(`agent workflow not found: ${id}`);
        return record;
    }
    save(record) {
        this.state.setUiState(this.scope, record.id, record);
    }
    activeWorkflowId() {
        return this.state.getUiState(this.scope, "active");
    }
    setActiveWorkflowId(id) {
        this.state.setUiState(this.scope, "active", id);
    }
    addMessage(workflowId, message) {
        const key = `messages:${workflowId}`;
        const messages = this.state.getUiState(this.scope, key) ?? [];
        this.state.setUiState(this.scope, key, [...messages, message].slice(-200));
    }
    messages(workflowId) {
        return this.state.getUiState(this.scope, `messages:${workflowId}`) ?? [];
    }
}
function normalizeRoles(roles, objective) {
    if (roles?.length) {
        return roles.map((role) => ({
            name: safeRoleName(role.name),
            responsibility: role.responsibility.trim(),
            skills: unique(role.skills),
            tools: unique(role.tools),
            acceptance: unique(role.acceptance),
        }));
    }
    return [
        {
            name: "planner",
            responsibility: `Clarify the work plan, break down tasks, and keep the workflow aligned with the objective: ${objective}`,
            skills: [],
            tools: ["TodoWrite", "read_file", "list_files", "grep_files"],
            acceptance: ["Task plan is clear and actionable."],
        },
        {
            name: "builder",
            responsibility: `Implement the concrete project work required by the objective: ${objective}`,
            skills: [],
            tools: ["read_file", "write_file", "append_file", "apply_patch", "invoke_skill", "mcp_call"],
            acceptance: ["Requested artifacts or code changes exist in the project."],
        },
    ];
}
function ensureReviewerRole(roles, acceptanceCriteria) {
    const hasReviewer = roles.some((role) => /review|验收|qa|test|验证/i.test(role.name));
    if (hasReviewer)
        return roles;
    return [
        ...roles,
        {
            name: "reviewer",
            responsibility: "Verify the final result, confirm requested artifacts exist, check obvious failures, and summarize remaining issues.",
            skills: [],
            tools: ["read_file", "list_files", "glob_files", "validate_artifact", "browser_screenshot"],
            acceptance: acceptanceCriteria.length
                ? acceptanceCriteria
                : ["Final artifacts exist.", "The result matches the user request.", "Known limitations are reported honestly."],
        },
    ];
}
function safeRoleName(value) {
    return value.trim().replace(/\s+/g, "_").replace(/[^\w\u4e00-\u9fa5-]/g, "").slice(0, 48) || "agent";
}
function unique(values) {
    return [...new Set((values ?? []).map((value) => value.trim()).filter(Boolean))];
}
