"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Pipeline = void 0;
const uuid_1 = require("uuid");
const migrations_js_1 = require("../migrations.js");
const index_js_1 = require("../services/index.js");
const util = __importStar(require("../util/index.js"));
const action_js_1 = require("./action.js");
const list_js_1 = require("./list.js");
const pipe_js_1 = require("./pipe.js");
class Pipeline extends list_js_1.EntityList {
    constructor($owner, key, spec) {
        const items = Array.isArray(spec) ? spec : spec?.pipes || spec?.items || [];
        super($owner, key, items);
        this.id = (0, uuid_1.v4)();
    }
    get $entityType() { return 'pipeline'; }
    get $action() {
        return this.$owner instanceof action_js_1.Action ? this.$owner : this.$owner.$action;
    }
    get $context() { return this.$owner.$context; }
    get $script() { return this.$owner.$script; }
    get $engine() { return this.$script.$engine; }
    get $browser() { return this.$script.$browser; }
    get $resolver() { return this.$engine.get(index_js_1.ResolverService); }
    get $idDatabase() { return this.$script; }
    create(spec) {
        spec = (0, migrations_js_1.migratePipeSpec)(util.cloneWithoutIdsCollision(spec || {}, this.$script.$ids));
        const PipeClass = this.$resolver.getPipeClass(spec.type);
        const pipe = new PipeClass(this);
        pipe.init(spec);
        return pipe;
    }
    getDepth() {
        if (this.$owner instanceof pipe_js_1.Pipe) {
            return this.$owner.getDepth() + 1;
        }
        return 0;
    }
    *descendentPipes() {
        for (const pipe of this.items) {
            yield pipe;
            for (const pipeline of pipe.collectPipelines()) {
                yield* pipeline.descendentPipes();
            }
        }
    }
    async selectAll(list, ctx) {
        if (ctx.$introspectionEnabled) {
            ctx.$introspectionResults.push({
                pipelineId: this.id,
                inputSet: list,
            });
            ctx.$introspectionStats.pipelinesExecuted += 1;
        }
        ctx.$stack.push({ pipeline: this, locals: new Map() });
        let nextInputSet = list;
        for (const pipe of this.items) {
            const startedAt = Date.now();
            try {
                ctx.pipe = pipe;
                const thisInputSet = nextInputSet;
                const outputSet = pipe.enabled ? await pipe.apply(thisInputSet, ctx) : thisInputSet;
                nextInputSet = outputSet;
                if (ctx.$introspectionEnabled) {
                    ctx.$introspectionStats.pipesExecuted += 1;
                    if (ctx.$introspectionSpotlight) {
                        const { pipeId, index } = ctx.$introspectionSpotlight;
                        if (pipeId === pipe.id) {
                            const el = outputSet[index];
                            nextInputSet = el ? [el] : outputSet;
                        }
                    }
                    ctx.$introspectionResults.push({
                        pipeId: pipe.id,
                        inputSet: thisInputSet,
                        outputSet,
                        nextInputSet,
                        error: null,
                        duration: Date.now() - startedAt,
                    });
                }
            }
            catch (error) {
                if (ctx.$introspectionEnabled) {
                    ctx.$introspectionResults.push({
                        pipeId: pipe.id,
                        inputSet: nextInputSet,
                        outputSet: null,
                        nextInputSet: null,
                        error,
                        duration: Date.now() - startedAt,
                    });
                }
                error.details = {
                    ...error.details,
                    pipeId: pipe.id,
                    pipeType: pipe.type,
                };
                throw error;
            }
        }
        ctx.$stack.pop();
        return nextInputSet;
    }
    async selectOne(inputSet, ctx) {
        const result = await this.selectOneOrNull(inputSet, ctx);
        if (result == null) {
            throw util.createError({
                code: 'NoResults',
                message: 'Expected at least one result, found none',
                retry: true,
            });
        }
        return result;
    }
    async selectOneOrNull(inputSet, ctx) {
        const results = await this.selectAll(inputSet, ctx);
        switch (results.length) {
            case 0:
                return null;
            case 1:
                return results[0];
            default:
                throw util.createError({
                    code: 'AmbiguousResults',
                    message: 'Expected single result, found multiple',
                    retry: true,
                });
        }
    }
}
exports.Pipeline = Pipeline;
//# sourceMappingURL=pipeline.js.map