"use strict";
/**
 * Build stage: construct the HotMesh YAML DAG from the compilation plan.
 *
 * When an EnhancedCompilationPlan is available, uses its iteration specs,
 * data flow edges, and key mappings to build a faithful deterministic DAG.
 * Falls back to mechanical heuristics when no plan is available.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.sanitizeToolName = exports.capToolArguments = void 0;
exports.build = build;
const input_analyzer_1 = require("../../input-analyzer");
const utils_1 = require("./utils");
const metadata_1 = require("./metadata");
const iteration_1 = require("./iteration");
const dag_1 = require("./dag");
// Re-export public utilities used by other modules
var utils_2 = require("./utils");
Object.defineProperty(exports, "capToolArguments", { enumerable: true, get: function () { return utils_2.capToolArguments; } });
var utils_3 = require("../../../../modules/utils");
Object.defineProperty(exports, "sanitizeToolName", { enumerable: true, get: function () { return utils_3.sanitizeToolName; } });
/**
 * Build pipeline stage: construct the HotMesh YAML DAG.
 *
 * Reads as a five-phase pipeline:
 *   1. Prepare inputs (schema, session fields, index mapping)
 *   2. Initialize the DAG with a trigger activity
 *   3. Append each step as an iteration or normal activity
 *   4. Serialize to YAML
 *   5. Derive metadata (tags, category)
 */
async function build(ctx) {
    const { options, coreSteps: steps, refinedInputs, compilationPlan: plan } = ctx;
    // 1. Prepare inputs
    const inputSchema = (0, input_analyzer_1.buildEnrichedInputSchema)(refinedInputs);
    const triggerInputKeys = new Set(refinedInputs.map(f => f.key));
    const sessionFields = resolveSessionFields(plan);
    const collapsedToCoreIndex = buildCoreStepIndexMap(plan, ctx.collapsedSteps);
    const outputSchema = inferOutputSchema(steps);
    const prefix = buildActivityPrefix(options.name);
    // 2. Initialize DAG with trigger
    const dag = (0, dag_1.initializeDag)(prefix, options.subscribes, inputSchema);
    // 3. Build each step — iteration, signal, or normal
    steps.forEach((step, idx) => {
        if (step.kind === 'signal') {
            (0, dag_1.appendSignalStep)(dag, idx, step, prefix, options.subscribes, plan, steps, triggerInputKeys, collapsedToCoreIndex);
            return;
        }
        const iterSpec = (0, iteration_1.findIterationSpec)(idx, plan, step, collapsedToCoreIndex);
        if (iterSpec) {
            (0, dag_1.appendIterationStep)(dag, iterSpec, prefix, options.subscribes, idx, step, triggerInputKeys, steps, sessionFields, plan);
        }
        else {
            (0, dag_1.appendNormalStep)(dag, idx, step, prefix, options.subscribes, plan, steps, triggerInputKeys, collapsedToCoreIndex);
        }
    });
    // 4. Serialize to YAML
    ctx.yaml = (0, dag_1.serializeToYaml)(options.appId, options.subscribes, inputSchema, outputSchema, dag);
    ctx.inputSchema = inputSchema;
    ctx.outputSchema = outputSchema;
    ctx.activityManifest = dag.manifest;
    // 5. Derive metadata
    ctx.tags = (0, metadata_1.deriveTagsFromSteps)(steps, options.name, options.description);
    ctx.category = await (0, metadata_1.deriveCategory)(steps);
    return ctx;
}
// ── Preparation helpers ──────────────────────────────────────────────────────
/** Resolve session fields from the compilation plan or use sensible defaults. */
function resolveSessionFields(plan) {
    return plan?.sessionFields?.length
        ? plan.sessionFields
        : ['page_id', '_handle', 'session_id'];
}
/**
 * Build a remapping from collapsed-step indices to core-step indices.
 *
 * The compilation plan uses indices from collapsedSteps, but after core-step
 * filtering those indices shift. This map translates between the two spaces.
 */
function buildCoreStepIndexMap(plan, collapsedSteps) {
    const map = new Map();
    if (plan && plan.coreStepIndices.length > 0 && plan.coreStepIndices.length < collapsedSteps.length) {
        plan.coreStepIndices.forEach((collapsedIdx, coreIdx) => {
            map.set(collapsedIdx, coreIdx);
        });
    }
    return map;
}
/** Infer an output schema from the last step's result. */
function inferOutputSchema(steps) {
    const lastStep = steps[steps.length - 1];
    return lastStep?.result
        ? (0, utils_1.inferSchema)(lastStep.result)
        : { type: 'object' };
}
/**
 * Build a sanitized activity-ID prefix from the graph topic.
 *
 * The prefix must be unique per graph to avoid activity ID collisions
 * when multiple graphs are merged into one app deployment. We use the
 * full sanitized topic (no truncation) plus a 4-char hash suffix when
 * the topic exceeds 20 chars, ensuring uniqueness even for topics that
 * share a long common prefix.
 */
function buildActivityPrefix(graphTopic) {
    const raw = graphTopic.replace(/[^a-z0-9]/g, '_');
    if (raw.length <= 20)
        return raw;
    // Short hash suffix to guarantee uniqueness across similar topics
    let hash = 0;
    for (let i = 0; i < graphTopic.length; i++) {
        hash = ((hash << 5) - hash + graphTopic.charCodeAt(i)) | 0;
    }
    const suffix = Math.abs(hash).toString(36).slice(0, 4);
    return `${raw.slice(0, 16)}_${suffix}`;
}
