import { readFileSync, readdirSync } from "node:fs";
import { createServer } from "node:http";
import { join } from "node:path";
import { parseArgs } from "node:util";
import { createOutcomesExportDocument, listAvailableArtifactKinds, listAvailableStatuses, listAvailableWorkflows, loadBenchmarkIndexView, loadOutcomesDashboardView, loadRunComparisonView, loadRunDetailView, loadRunsIndexView, parseOutcomesFilters, resolveBenchmarkLedgerPath, resolveRunsRoot, toRelativeDisplayPath } from "./data.js";
import { renderBenchmarksPage, renderConfigurePage, renderOutcomesDashboardPage, renderOutcomesExportMarkdown, renderRunComparePage, renderRunDetailPage, renderRunsIndexPage, visualizerStyles } from "./html.js";
function json(response, statusCode, body) {
    response.writeHead(statusCode, { "content-type": "application/json; charset=utf-8" });
    response.end(JSON.stringify(body, null, 2));
}
function html(response, statusCode, body) {
    response.writeHead(statusCode, { "content-type": "text/html; charset=utf-8" });
    response.end(body);
}
function redirect(response, location) {
    response.writeHead(302, { location });
    response.end();
}
function text(response, statusCode, body, contentType = "text/plain; charset=utf-8") {
    response.writeHead(statusCode, { "content-type": contentType });
    response.end(body);
}
function notFound(response) {
    html(response, 404, `<!doctype html><html><body><h1>Not found</h1><p>The requested visualizer resource does not exist.</p></body></html>`);
}
function toFilters(searchParams) {
    return {
        search: searchParams.get("search") ?? undefined,
        workflow: searchParams.get("workflow") ?? undefined,
        status: searchParams.get("status") ?? undefined,
        artifactKind: searchParams.get("artifactKind") ?? undefined,
        decisionImpact: searchParams.get("decisionImpact") ?? undefined,
        riskKind: searchParams.get("riskKind") ?? undefined,
        evidenceCategory: searchParams.get("evidenceCategory") ?? undefined,
        evidenceStatus: searchParams.get("evidenceStatus") ?? undefined,
        hasOverride: searchParams.get("hasOverride") ?? undefined,
        workflowStage: searchParams.get("workflowStage") ?? undefined
    };
}
function workflowRequestPath(workflow) {
    const mapping = {
        "planning-discovery": ".agentops/requests/planning.yaml",
        "architecture-design-review": ".agentops/requests/design.yaml",
        "implementation-proposal": ".agentops/requests/implementation.yaml",
        "qa-review": ".agentops/requests/qa.yaml",
        "security-review": ".agentops/requests/security.yaml",
        "pipeline-evidence-review": ".agentops/requests/pipeline.yaml",
        "release-readiness": ".agentops/requests/release.yaml",
        "deployment-gate-review": ".agentops/requests/deployment.yaml",
        "promotion-approval": ".agentops/requests/promotion.yaml",
        "incident-handoff": ".agentops/requests/incident.yaml",
        "maintenance-triage": ".agentops/requests/maintenance.yaml"
    };
    return mapping[workflow];
}
function listRepoWorkflows(workspaceRoot) {
    const workflowsRoot = join(workspaceRoot, ".agentops", "workflows");
    return readdirSync(workflowsRoot)
        .filter((entry) => entry.endsWith(".yaml"))
        .map((entry) => entry.replace(/\.yaml$/, ""))
        .sort();
}
function assertSafeWorkflowName(workflow) {
    if (workflow === undefined || workflow === "") {
        return undefined;
    }
    if (!/^[a-z0-9-]+$/i.test(workflow)) {
        throw new Error("Workflow name must be a simple slug.");
    }
    return workflow;
}
function resolveConfigPath(workspaceRoot, workflow, target) {
    const safeWorkflow = assertSafeWorkflowName(workflow);
    if (target === "repo-fit") {
        return {
            path: join(workspaceRoot, ".agentops", "repo-fit.yaml"),
            relativePath: ".agentops/repo-fit.yaml"
        };
    }
    if (target === "policy-presets") {
        return {
            path: join(workspaceRoot, ".agentops", "control", "policy-presets.yaml"),
            relativePath: ".agentops/control/policy-presets.yaml"
        };
    }
    if (target === "defaults") {
        return {
            path: join(workspaceRoot, ".agentops", "control", "defaults.yaml"),
            relativePath: ".agentops/control/defaults.yaml"
        };
    }
    if (target === "workflow-control") {
        if (!safeWorkflow) {
            throw new Error("Workflow is required for workflow-control edits.");
        }
        return {
            path: join(workspaceRoot, ".agentops", "control", `${safeWorkflow}.yaml`),
            relativePath: `.agentops/control/${safeWorkflow}.yaml`
        };
    }
    if (target === "request") {
        const requestPath = safeWorkflow ? workflowRequestPath(safeWorkflow) : undefined;
        if (!requestPath) {
            throw new Error("Workflow is required for request edits.");
        }
        return {
            path: join(workspaceRoot, requestPath),
            relativePath: requestPath
        };
    }
    throw new Error(`Unsupported configure target: ${target}`);
}
function readConfigDocument(workspaceRoot, workflow, target) {
    const resolved = resolveConfigPath(workspaceRoot, workflow, target);
    return {
        ...resolved,
        contents: readFileSync(resolved.path, "utf8")
    };
}
function readJsonBody(request) {
    return new Promise((resolve, reject) => {
        const chunks = [];
        request.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
        request.on("end", () => {
            try {
                const raw = Buffer.concat(chunks).toString("utf8");
                resolve(raw.length > 0 ? JSON.parse(raw) : {});
            }
            catch (error) {
                reject(error);
            }
        });
        request.on("error", reject);
    });
}
export function createVisualizerServer(options) {
    const workspaceRoot = options.workspaceRoot;
    const runsRoot = resolveRunsRoot(workspaceRoot, options.runsRoot);
    const benchmarkLedgerPath = resolveBenchmarkLedgerPath(workspaceRoot, options.benchmarkLedgerPath);
    const configEditor = options.configEditor;
    return createServer((request, response) => {
        const url = new URL(request.url ?? "/", `http://${request.headers.host ?? "127.0.0.1"}`);
        const pathname = url.pathname;
        if (pathname === "/styles.css") {
            text(response, 200, visualizerStyles(), "text/css; charset=utf-8");
            return;
        }
        if (pathname === "/favicon.ico") {
            response.writeHead(204);
            response.end();
            return;
        }
        if (pathname === "/") {
            redirect(response, "/outcomes");
            return;
        }
        if (pathname === "/runs") {
            const view = loadRunsIndexView(workspaceRoot, runsRoot, toFilters(url.searchParams), benchmarkLedgerPath);
            html(response, 200, renderRunsIndexPage(view.runs, view.invalidRuns, toFilters(url.searchParams), {
                workflows: listAvailableWorkflows(view.runs),
                statuses: listAvailableStatuses(view.runs),
                artifactKinds: listAvailableArtifactKinds(view.runs),
                decisionImpacts: [...new Set(view.runs.flatMap((run) => (run.decisionImpactKind ? [run.decisionImpactKind] : [])))].sort(),
                riskKinds: [...new Set(view.runs.flatMap((run) => run.riskKinds))].sort(),
                evidenceCategories: [...new Set(view.runs.flatMap((run) => run.evidenceStatuses.map((status) => status.category)))].sort(),
                workflowStages: [...new Set(view.runs.flatMap((run) => (run.workflowStage ? [run.workflowStage] : [])))].sort()
            }));
            return;
        }
        if (pathname === "/benchmarks") {
            const view = loadBenchmarkIndexView(workspaceRoot, runsRoot, benchmarkLedgerPath);
            html(response, 200, renderBenchmarksPage(view));
            return;
        }
        if (pathname === "/configure") {
            const workflow = url.searchParams.get("workflow") ?? undefined;
            const target = url.searchParams.get("target") ?? "request";
            html(response, 200, renderConfigurePage({
                workflow,
                target,
                availableWorkflows: listRepoWorkflows(workspaceRoot),
                editingEnabled: configEditor?.editingEnabled ?? false
            }));
            return;
        }
        if (pathname === "/runs/compare") {
            const left = url.searchParams.get("left") ?? undefined;
            const right = url.searchParams.get("right") ?? undefined;
            const comparison = left && right ? loadRunComparisonView(workspaceRoot, left, right, runsRoot, benchmarkLedgerPath) : undefined;
            html(response, 200, renderRunComparePage(comparison, left, right));
            return;
        }
        if (pathname === "/value") {
            const suffix = url.search ? `${url.search}` : "";
            const hashless = `/outcomes${suffix}`;
            redirect(response, hashless);
            return;
        }
        if (pathname === "/outcomes") {
            const view = loadOutcomesDashboardView(workspaceRoot, runsRoot, benchmarkLedgerPath, parseOutcomesFilters(url.searchParams));
            html(response, 200, renderOutcomesDashboardPage(view));
            return;
        }
        if (pathname === "/api/runs") {
            const view = loadRunsIndexView(workspaceRoot, runsRoot, toFilters(url.searchParams), benchmarkLedgerPath);
            json(response, 200, view);
            return;
        }
        if (pathname === "/api/benchmarks") {
            json(response, 200, loadBenchmarkIndexView(workspaceRoot, runsRoot, benchmarkLedgerPath));
            return;
        }
        if (pathname === "/api/value" || pathname === "/api/outcomes") {
            json(response, 200, loadOutcomesDashboardView(workspaceRoot, runsRoot, benchmarkLedgerPath, parseOutcomesFilters(url.searchParams)));
            return;
        }
        if (pathname === "/api/runs/compare") {
            const left = url.searchParams.get("left");
            const right = url.searchParams.get("right");
            if (!left || !right) {
                json(response, 400, { error: "Provide left and right run ids." });
                return;
            }
            const comparison = loadRunComparisonView(workspaceRoot, left, right, runsRoot, benchmarkLedgerPath);
            if (!comparison) {
                json(response, 404, { error: "Run comparison could not be built." });
                return;
            }
            json(response, 200, comparison);
            return;
        }
        if (pathname === "/api/config/current") {
            try {
                const workflow = url.searchParams.get("workflow") ?? undefined;
                const target = url.searchParams.get("target") ?? "request";
                json(response, 200, readConfigDocument(workspaceRoot, workflow, target));
            }
            catch (error) {
                json(response, 400, { error: error instanceof Error ? error.message : "Failed to load config document." });
            }
            return;
        }
        if (pathname === "/api/config/editor") {
            const loadEditorModel = configEditor?.loadEditorModel;
            if (!loadEditorModel) {
                json(response, 501, { error: "Config editor model is unavailable." });
                return;
            }
            const workflow = url.searchParams.get("workflow") ?? undefined;
            const target = (url.searchParams.get("target") ?? "request");
            void Promise.resolve(loadEditorModel({ workflow, target }))
                .then((model) => {
                json(response, 200, model);
            })
                .catch((error) => {
                json(response, 400, { error: error instanceof Error ? error.message : "Failed to load config editor model." });
            });
            return;
        }
        if (request.method === "POST" && pathname === "/api/config/render") {
            const renderDocument = configEditor?.renderDocument;
            if (!renderDocument) {
                json(response, 501, { error: "Config document rendering is unavailable." });
                return;
            }
            void readJsonBody(request)
                .then(async (body) => {
                const payload = body;
                if (!payload.target) {
                    json(response, 400, { error: "Render requires target and state." });
                    return;
                }
                json(response, 200, await renderDocument({
                    workflow: payload.workflow,
                    target: payload.target,
                    state: payload.state
                }));
            })
                .catch((error) => {
                json(response, 400, { error: error instanceof Error ? error.message : "Failed to render config document." });
            });
            return;
        }
        if (request.method === "POST" && pathname === "/api/config/preview") {
            if (!configEditor?.editingEnabled || !configEditor.previewDocument) {
                json(response, 403, { error: "Config editing is disabled for this repository." });
                return;
            }
            const previewDocument = configEditor.previewDocument;
            void readJsonBody(request)
                .then(async (body) => {
                const payload = body;
                if (!payload.target || typeof payload.draft !== "string") {
                    json(response, 400, { error: "Preview requires target and draft." });
                    return;
                }
                json(response, 200, await previewDocument({
                    workflow: payload.workflow,
                    target: payload.target,
                    draft: payload.draft
                }));
            })
                .catch((error) => {
                json(response, 400, { error: error instanceof Error ? error.message : "Failed to preview config document." });
            });
            return;
        }
        if (request.method === "POST" && pathname === "/api/config/save") {
            if (!configEditor?.editingEnabled || !configEditor.saveDocument) {
                json(response, 403, { error: "Config editing is disabled for this repository." });
                return;
            }
            const saveDocument = configEditor.saveDocument;
            void readJsonBody(request)
                .then(async (body) => {
                const payload = body;
                if (!payload.target || typeof payload.draft !== "string" || typeof payload.previewHash !== "string" || typeof payload.approval !== "string") {
                    json(response, 400, { error: "Save requires target, draft, previewHash, and approval." });
                    return;
                }
                json(response, 200, await saveDocument({
                    workflow: payload.workflow,
                    target: payload.target,
                    draft: payload.draft,
                    previewHash: payload.previewHash,
                    approval: payload.approval
                }));
            })
                .catch((error) => {
                json(response, 400, { error: error instanceof Error ? error.message : "Failed to save config document." });
            });
            return;
        }
        if (pathname === "/api/outcomes/export.json") {
            json(response, 200, createOutcomesExportDocument(workspaceRoot, runsRoot, benchmarkLedgerPath, parseOutcomesFilters(url.searchParams)));
            return;
        }
        if (pathname === "/outcomes/export.md") {
            text(response, 200, renderOutcomesExportMarkdown(createOutcomesExportDocument(workspaceRoot, runsRoot, benchmarkLedgerPath, parseOutcomesFilters(url.searchParams))), "text/markdown; charset=utf-8");
            return;
        }
        const runDetailMatch = pathname.match(/^\/runs\/([^/]+)$/);
        if (runDetailMatch) {
            const run = loadRunDetailView(workspaceRoot, decodeURIComponent(runDetailMatch[1] ?? ""), runsRoot, benchmarkLedgerPath);
            if (!run) {
                notFound(response);
                return;
            }
            html(response, 200, renderRunDetailPage(run));
            return;
        }
        const runApiMatch = pathname.match(/^\/api\/runs\/([^/]+)$/);
        if (runApiMatch) {
            const run = loadRunDetailView(workspaceRoot, decodeURIComponent(runApiMatch[1] ?? ""), runsRoot, benchmarkLedgerPath);
            if (!run) {
                json(response, 404, { error: "Run not found." });
                return;
            }
            json(response, 200, run);
            return;
        }
        const rawBundleMatch = pathname.match(/^\/api\/runs\/([^/]+)\/bundle\.json$/);
        if (rawBundleMatch) {
            const run = loadRunDetailView(workspaceRoot, decodeURIComponent(rawBundleMatch[1] ?? ""), runsRoot, benchmarkLedgerPath);
            if (!run) {
                json(response, 404, { error: "Run not found." });
                return;
            }
            text(response, 200, run.rawBundleJson, "application/json; charset=utf-8");
            return;
        }
        const rawSummaryMatch = pathname.match(/^\/api\/runs\/([^/]+)\/summary\.md$/);
        if (rawSummaryMatch) {
            const run = loadRunDetailView(workspaceRoot, decodeURIComponent(rawSummaryMatch[1] ?? ""), runsRoot, benchmarkLedgerPath);
            if (!run) {
                json(response, 404, { error: "Run not found." });
                return;
            }
            text(response, 200, run.summaryMarkdown, "text/markdown; charset=utf-8");
            return;
        }
        notFound(response);
    });
}
export async function startVisualizerServer(options) {
    const host = options.host ?? "127.0.0.1";
    const port = options.port ?? 4313;
    const runsRoot = resolveRunsRoot(options.workspaceRoot, options.runsRoot);
    const server = createVisualizerServer({ ...options, host, port, runsRoot });
    await new Promise((resolvePromise) => {
        server.listen(port, host, () => resolvePromise());
    });
    const address = server.address();
    const boundPort = typeof address === "object" && address ? address.port : port;
    return {
        serverUrl: `http://${host}:${boundPort}`,
        runsRoot,
        close: async () => await new Promise((resolvePromise, reject) => {
            server.close((error) => {
                if (error) {
                    reject(error);
                    return;
                }
                resolvePromise();
            });
        })
    };
}
export function readVisualizerSummary(workspaceRoot, runsRoot) {
    const resolvedRunsRoot = resolveRunsRoot(workspaceRoot, runsRoot);
    const runsView = loadRunsIndexView(workspaceRoot, resolvedRunsRoot);
    const benchmarksView = loadBenchmarkIndexView(workspaceRoot, resolvedRunsRoot);
    return {
        runsRoot: toRelativeDisplayPath(workspaceRoot, resolvedRunsRoot),
        runCount: runsView.runs.length,
        benchmarkCount: benchmarksView.benchmarks.length
    };
}
export function parseVisualizerServerArgs(argv) {
    const normalizedArgs = argv[0] === "--" ? argv.slice(1) : argv;
    const parsed = parseArgs({
        args: normalizedArgs,
        options: {
            host: { type: "string" },
            port: { type: "string" },
            "runs-root": { type: "string" },
            "benchmark-ledger": { type: "string" }
        },
        allowPositionals: false
    });
    return {
        host: parsed.values.host,
        port: parsed.values.port ? Number.parseInt(parsed.values.port, 10) : undefined,
        runsRoot: parsed.values["runs-root"],
        benchmarkLedgerPath: parsed.values["benchmark-ledger"]
    };
}
export { createOutcomesExportDocument, listAvailableArtifactKinds, listAvailableStatuses, listAvailableWorkflows, loadBenchmarkIndexView, loadOutcomesDashboardView, loadRunDetailView, loadRunsIndexView, parseOutcomesFilters, resolveBenchmarkLedgerPath, resolveRunsRoot, toRelativeDisplayPath } from "./data.js";
export { renderOutcomesExportMarkdown } from "./html.js";
//# sourceMappingURL=index.js.map