"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LockedData = void 0;
const guards_1 = require("./guards");
const step_validator_1 = require("./step-validator");
const printer_1 = require("./printer");
class LockedData {
    constructor(baseDir) {
        this.baseDir = baseDir;
        this.flows = {};
        this.activeSteps = [];
        this.devSteps = [];
        this.stepsMap = {};
        this.printer = new printer_1.Printer(baseDir);
        this.handlers = {
            'flow-created': [],
            'flow-removed': [],
            'flow-updated': [],
        };
        this.stepHandlers = {
            'step-created': [],
            'step-removed': [],
            'step-updated': [],
        };
    }
    on(event, handler) {
        this.handlers[event].push(handler);
    }
    onStep(event, handler) {
        this.stepHandlers[event].push(handler);
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    eventSteps() {
        return this.activeSteps.filter(guards_1.isEventStep);
    }
    apiSteps() {
        return this.activeSteps.filter(guards_1.isApiStep);
    }
    cronSteps() {
        return this.activeSteps.filter(guards_1.isCronStep);
    }
    updateStep(oldStep, newStep) {
        if (!this.isValidStep(newStep)) {
            this.deleteStep(oldStep);
            return false;
        }
        if (oldStep.config.type !== newStep.config.type) {
            this.activeSteps = this.activeSteps.filter((s) => s.filePath !== oldStep.filePath);
            this.devSteps = this.devSteps.filter((s) => s.filePath !== oldStep.filePath);
            if (newStep.config.type === 'noop') {
                this.devSteps.push(newStep);
            }
            else {
                this.activeSteps.push(newStep);
            }
        }
        const savedStep = this.stepsMap[newStep.filePath];
        const addedFlows = newStep.config.flows?.filter((flowName) => !oldStep.config.flows?.includes(flowName)) ?? [];
        const removedFlows = oldStep.config.flows?.filter((flowName) => !newStep.config.flows?.includes(flowName)) ?? [];
        const untouchedFlows = oldStep.config.flows?.filter((flowName) => newStep.config.flows?.includes(flowName)) ?? [];
        untouchedFlows.forEach((flowName) => this.onFlowUpdated(flowName));
        for (const flowName of addedFlows) {
            if (!this.flows[flowName]) {
                const flow = this.createFlow(flowName);
                flow.steps.push(savedStep);
            }
            else {
                this.flows[flowName].steps.push(savedStep);
                this.onFlowUpdated(flowName);
            }
        }
        for (const flowName of removedFlows) {
            const flowSteps = this.flows[flowName].steps;
            this.flows[flowName].steps = flowSteps.filter(({ filePath }) => filePath !== newStep.filePath);
            if (this.flows[flowName].steps.length === 0) {
                this.removeFlow(flowName);
            }
            else {
                this.onFlowUpdated(flowName);
            }
        }
        savedStep.config = newStep.config;
        this.stepHandlers['step-updated'].forEach((handler) => handler(newStep));
        this.printer.printStepUpdated(newStep);
        return true;
    }
    createStep(step) {
        if (!this.isValidStep(step)) {
            return false;
        }
        this.stepsMap[step.filePath] = step;
        if (step.config.type === 'noop') {
            this.devSteps.push(step);
        }
        else {
            this.activeSteps.push(step);
        }
        for (const flowName of step.config.flows ?? []) {
            if (!this.flows[flowName]) {
                const flow = this.createFlow(flowName);
                flow.steps.push(step);
            }
            else {
                this.flows[flowName].steps.push(step);
                this.onFlowUpdated(flowName);
            }
        }
        this.stepHandlers['step-created'].forEach((handler) => handler(step));
        this.printer.printStepCreated(step);
        return true;
    }
    deleteStep(step) {
        // Remove step from active and dev steps
        this.activeSteps = this.activeSteps.filter(({ filePath }) => filePath !== step.filePath);
        this.devSteps = this.devSteps.filter(({ filePath }) => filePath !== step.filePath);
        delete this.stepsMap[step.filePath];
        for (const flowName of step.config.flows ?? []) {
            const stepFlows = this.flows[flowName]?.steps;
            if (stepFlows) {
                this.flows[flowName].steps = stepFlows.filter(({ filePath }) => filePath !== step.filePath);
            }
            if (this.flows[flowName].steps.length === 0) {
                this.removeFlow(flowName);
            }
            else {
                this.onFlowUpdated(flowName);
            }
        }
        this.stepHandlers['step-removed'].forEach((handler) => handler(step));
        this.printer.printStepRemoved(step);
    }
    createFlow(flowName) {
        const flow = { name: flowName, description: '', steps: [] };
        this.flows[flowName] = flow;
        this.handlers['flow-created'].forEach((handler) => handler(flowName));
        this.printer.printFlowCreated(flowName);
        return flow;
    }
    removeFlow(flowName) {
        delete this.flows[flowName];
        this.handlers['flow-removed'].forEach((handler) => handler(flowName));
        this.printer.printFlowRemoved(flowName);
    }
    onFlowUpdated(flowName) {
        this.handlers['flow-updated'].forEach((handler) => handler(flowName));
    }
    isValidStep(step) {
        const validationResult = (0, step_validator_1.validateStep)(step);
        if (!validationResult.success) {
            this.printer.printValidationError(step.filePath, validationResult);
        }
        return validationResult.success;
    }
}
exports.LockedData = LockedData;
