import * as z from "zod/v4";
import { jsonResult, errorResult, mixedResult } from "../utils/response-formatter.js";
import { toProjectHealthData, renderStatusSummarySvg } from "../utils/svg/index.js";
import { buildDeepLink } from "../utils/deep-links.js";
import { isUserError, isUserFixableApiError, toMcpError } from "../utils/errors.js";
import { createLogger } from "../utils/logger.js";
import { sendProgress } from "../utils/progress.js";
import { applyUrlDefaults } from "../utils/url-parser.js";
import { asString } from "../utils/type-guards.js";
import { statusOutputSchema } from "./output-schemas.js";
const log = createLogger("status");
function summarizeExecution(exec, baseUrl, accountId, orgId, projectId) {
    const summary = {
        execution_id: exec.planExecutionId,
        pipeline: exec.pipelineIdentifier,
        name: exec.name,
        status: exec.status,
        started_at: exec.startTs ? new Date(exec.startTs).toISOString() : undefined,
        ended_at: exec.endTs ? new Date(exec.endTs).toISOString() : undefined,
    };
    if (exec.planExecutionId && exec.pipelineIdentifier) {
        try {
            summary.openInHarness = buildDeepLink(baseUrl, accountId, "/ng/account/{accountId}/all/orgs/{orgIdentifier}/projects/{projectIdentifier}/pipelines/{pipelineIdentifier}/deployments/{planExecutionId}/pipeline", {
                orgIdentifier: orgId,
                projectIdentifier: projectId,
                pipelineIdentifier: exec.pipelineIdentifier,
                planExecutionId: exec.planExecutionId,
            });
        }
        catch {
            // non-critical
        }
    }
    return summary;
}
export function registerStatusTool(server, registry, client, config) {
    server.registerTool("harness_status", {
        description: "Get a live project health overview: recent failed executions, currently running executions, and recent deployment activity. You can pass a Harness URL to auto-extract org and project. Ideal first question: 'what's happening in my project right now?'",
        inputSchema: {
            org_id: z.string().describe("Organization identifier (overrides default)").optional(),
            project_id: z.string().describe("Project identifier (overrides default)").optional(),
            url: z.string().describe("A Harness UI URL — org and project are extracted automatically").optional(),
            limit: z.number().describe("Max items per section (default 5, max 20)").default(5).optional(),
            include_visual: z.boolean().describe("Include visual health dashboard image (default false)").default(false).optional(),
        },
        outputSchema: statusOutputSchema,
        annotations: {
            title: "Project Health Status",
            readOnlyHint: true,
            destructiveHint: false,
            openWorldHint: true,
        },
    }, async (args, extra) => {
        try {
            const signal = extra.signal;
            const merged = applyUrlDefaults(args, args.url);
            const orgId = asString(merged.org_id) ?? config.HARNESS_ORG;
            const projectId = asString(merged.project_id) ?? config.HARNESS_PROJECT;
            const limit = Math.min(args.limit ?? 5, 20);
            if (!orgId) {
                return errorResult("org_id is required. Pass org_id or set HARNESS_ORG.");
            }
            if (!projectId) {
                return errorResult("project_id is required. Pass project_id or set HARNESS_PROJECT.");
            }
            const baseInput = {
                org_id: orgId,
                project_id: projectId,
                size: limit,
                page: 0,
            };
            log.info("Fetching project status", { orgId, projectId, limit });
            await sendProgress(extra, 0, 2, "Fetching failed, running, and recent executions...");
            // 3 parallel dispatches: failed, running, recent activity
            const [failedResult, runningResult, recentResult] = await Promise.allSettled([
                registry.dispatch(client, "execution", "list", {
                    ...baseInput,
                    status: "Failed",
                }, { tool: "harness_status" }, signal),
                registry.dispatch(client, "execution", "list", {
                    ...baseInput,
                    status: "Running",
                }, { tool: "harness_status" }, signal),
                registry.dispatch(client, "execution", "list", {
                    ...baseInput,
                    size: Math.min(limit * 2, 20),
                }, { tool: "harness_status" }, signal),
            ]);
            // Extract results with graceful degradation
            const failed = failedResult.status === "fulfilled"
                ? failedResult.value
                : null;
            const running = runningResult.status === "fulfilled"
                ? runningResult.value
                : null;
            const recent = recentResult.status === "fulfilled"
                ? recentResult.value
                : null;
            if (failedResult.status === "rejected") {
                log.warn("Failed to fetch failed executions", { error: String(failedResult.reason) });
            }
            if (runningResult.status === "rejected") {
                log.warn("Failed to fetch running executions", { error: String(runningResult.reason) });
            }
            if (recentResult.status === "rejected") {
                log.warn("Failed to fetch recent executions", { error: String(recentResult.reason) });
            }
            await sendProgress(extra, 1, 2, "Building status summary...");
            const accountId = registry.getAccountId();
            const failedItems = (failed?.items ?? []).map((e) => summarizeExecution(e, config.HARNESS_BASE_URL, accountId, orgId, projectId));
            const runningItems = (running?.items ?? []).map((e) => summarizeExecution(e, config.HARNESS_BASE_URL, accountId, orgId, projectId));
            const recentItems = (recent?.items ?? []).map((e) => summarizeExecution(e, config.HARNESS_BASE_URL, accountId, orgId, projectId));
            // Compute health
            const totalFailed = failed?.total ?? failedItems.length;
            const totalRunning = running?.total ?? runningItems.length;
            const totalRecent = recent?.total ?? recentItems.length;
            let health;
            if (totalFailed === 0) {
                health = "healthy";
            }
            else if (totalRecent > 0 && totalFailed < totalRecent) {
                health = "degraded";
            }
            else {
                health = "failing";
            }
            // Build project-level deployments deep link
            let deploymentsLink;
            try {
                deploymentsLink = buildDeepLink(config.HARNESS_BASE_URL, accountId, "/ng/account/{accountId}/all/orgs/{orgIdentifier}/projects/{projectIdentifier}/deployments", { orgIdentifier: orgId, projectIdentifier: projectId });
            }
            catch {
                // non-critical
            }
            // Collect errors from rejected promises
            const errors = {};
            if (failedResult.status === "rejected")
                errors.failed = String(failedResult.reason);
            if (runningResult.status === "rejected")
                errors.running = String(runningResult.reason);
            if (recentResult.status === "rejected")
                errors.recent = String(recentResult.reason);
            await sendProgress(extra, 2, 2, "Status complete");
            const status = {
                project: {
                    org: orgId,
                    project: projectId,
                    url: deploymentsLink,
                },
                failed_executions: failedItems,
                running_executions: runningItems,
                recent_activity: recentItems,
                summary: {
                    total_failed: totalFailed,
                    total_running: totalRunning,
                    total_recent: totalRecent,
                    health,
                },
                openInHarness: deploymentsLink,
            };
            if (Object.keys(errors).length > 0) {
                status._errors = errors;
            }
            // Visual rendering (opt-in)
            if (args.include_visual) {
                try {
                    const healthData = toProjectHealthData(status, orgId, projectId);
                    if (healthData) {
                        const svg = renderStatusSummarySvg(healthData);
                        return await mixedResult(status, svg);
                    }
                }
                catch (err) {
                    log.warn("SVG rendering failed, returning text-only", { error: String(err) });
                }
            }
            return jsonResult(status);
        }
        catch (err) {
            if (isUserError(err))
                return errorResult(err.message);
            if (isUserFixableApiError(err))
                return errorResult(err.message);
            throw toMcpError(err);
        }
    });
}
//# sourceMappingURL=harness-status.js.map