// this is a store that tracks the app context
// it will contain the app and page scopes
// entity names and types
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
    var useValue = arguments.length > 2;
    for (var i = 0; i < initializers.length; i++) {
        value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
    }
    return useValue ? value : void 0;
};
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
    function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
    var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
    var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
    var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
    var _, done = false;
    for (var i = decorators.length - 1; i >= 0; i--) {
        var context = {};
        for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
        for (var p in contextIn.access) context.access[p] = contextIn.access[p];
        context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
        var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
        if (kind === "accessor") {
            if (result === void 0) continue;
            if (result === null || typeof result !== "object") throw new TypeError("Object expected");
            if (_ = accept(result.get)) descriptor.get = _;
            if (_ = accept(result.set)) descriptor.set = _;
            if (_ = accept(result.init)) initializers.unshift(_);
        }
        else if (_ = accept(result)) {
            if (kind === "field") initializers.unshift(_);
            else descriptor[key] = _;
        }
    }
    if (target) Object.defineProperty(target, contextIn.name, descriptor);
    done = true;
};
import { isWidgetNode, isHTMLElementNode, NATIVE_COMPONENT_TYPES, } from "@superblocksteam/library-shared";
import { ComponentsManager } from "../../components-manager.js";
import llmobs from "../llmobs/index.js";
// copied from shared
const ALL_BLOCK_TYPES = [
    "break",
    "return",
    "wait",
    "throw",
    "parallel",
    "conditional",
    "loop",
    "tryCatch",
    "step",
    "variables",
    "send",
    "stream",
];
let AppContextStore = (() => {
    let _instanceExtraInitializers = [];
    let _handleApiUpdate_decorators;
    let _handleAppScopeReset_decorators;
    let _getComponentsForApp_decorators;
    let _getComponentCountByPage_decorators;
    return class AppContextStore {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
            _handleApiUpdate_decorators = [llmobs.decorate({ kind: "task", name: "AppContextStore.handleApiUpdate" })];
            _handleAppScopeReset_decorators = [llmobs.decorate({
                    kind: "task",
                    name: "AppContextStore.handleAppScopeReset",
                })];
            _getComponentsForApp_decorators = [llmobs.decorate({
                    kind: "task",
                    name: "AppContextStore.getComponentsForApp",
                })];
            _getComponentCountByPage_decorators = [llmobs.decorate({
                    kind: "task",
                    name: "AppContextStore.getComponentCountByPage",
                })];
            __esDecorate(this, null, _handleApiUpdate_decorators, { kind: "method", name: "handleApiUpdate", static: false, private: false, access: { has: obj => "handleApiUpdate" in obj, get: obj => obj.handleApiUpdate }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _handleAppScopeReset_decorators, { kind: "method", name: "handleAppScopeReset", static: false, private: false, access: { has: obj => "handleAppScopeReset" in obj, get: obj => obj.handleAppScopeReset }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _getComponentsForApp_decorators, { kind: "method", name: "getComponentsForApp", static: false, private: false, access: { has: obj => "getComponentsForApp" in obj, get: obj => obj.getComponentsForApp }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _getComponentCountByPage_decorators, { kind: "method", name: "getComponentCountByPage", static: false, private: false, access: { has: obj => "getComponentCountByPage" in obj, get: obj => obj.getComponentCountByPage }, metadata: _metadata }, null, _instanceExtraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        componentSemanticsById = (__runInitializers(this, _instanceExtraInitializers), {});
        apiSemanticsByName = {};
        appScopeId;
        pageNames = new Set();
        fileSystemInterface;
        constructor(fileSystemInterface) {
            this.fileSystemInterface = fileSystemInterface;
        }
        extractSemanticProperties(properties) {
            const semanticProperties = {};
            const propsToExtract = [
                "backgroundColor",
                "textColor",
                "icon",
                "width",
                "height",
                "text",
                "label",
                "title",
                "headerText",
                "buttonStyle",
            ];
            for (const propName of propsToExtract) {
                if (properties[propName] && properties[propName].value !== undefined) {
                    semanticProperties[propName] = properties[propName].value;
                }
            }
            return semanticProperties;
        }
        getBlockType(block) {
            for (const type of ALL_BLOCK_TYPES) {
                if (type in block) {
                    return type;
                }
            }
            return undefined;
        }
        getPluginType(block) {
            if (block.step) {
                // it's the key in the step config that isn't 'integration'
                return Object.keys(block.step).find((k) => k !== "integration");
            }
            return undefined;
        }
        extractBlockInfo(blocks = []) {
            const results = [];
            for (const block of blocks) {
                const type = this.getBlockType(block);
                if (!type)
                    continue;
                const pluginType = this.getPluginType(block);
                const id = block.step?.integration;
                results.push({
                    name: block.name,
                    type,
                    pluginType,
                    id: id === pluginType ? undefined : id,
                });
                // Recursively process nested blocks
                if (block.conditional) {
                    const { if: ifCond, elseIf, else: elseCond } = block.conditional;
                    if (ifCond?.blocks) {
                        results.push(...this.extractBlockInfo(ifCond.blocks));
                    }
                    if (elseIf) {
                        for (const cond of elseIf) {
                            if (cond.blocks) {
                                results.push(...this.extractBlockInfo(cond.blocks));
                            }
                        }
                    }
                    if (elseCond?.blocks) {
                        results.push(...this.extractBlockInfo(elseCond.blocks));
                    }
                }
                else if (block.loop?.blocks) {
                    results.push(...this.extractBlockInfo(block.loop.blocks));
                }
                else if (block.tryCatch) {
                    const { try: tryBlock, catch: catchBlock, finally: finallyBlock, } = block.tryCatch;
                    if (tryBlock?.blocks) {
                        results.push(...this.extractBlockInfo(tryBlock.blocks));
                    }
                    if (catchBlock?.blocks) {
                        results.push(...this.extractBlockInfo(catchBlock.blocks));
                    }
                    if (finallyBlock?.blocks) {
                        results.push(...this.extractBlockInfo(finallyBlock.blocks));
                    }
                }
                else if (block.parallel?.static?.paths) {
                    for (const path of Object.values(block.parallel.static.paths)) {
                        if (path.blocks) {
                            results.push(...this.extractBlockInfo(path.blocks));
                        }
                    }
                }
            }
            return results;
        }
        extractApiSemantics(apis = []) {
            const apiSemantics = {};
            for (const api of apis) {
                // Extract page name from API id: <pageName>_<apiName>
                const pageName = api.id.split("_")[0] || "unknown";
                apiSemantics[api.name] = {
                    name: api.name,
                    pageName,
                    blocks: this.extractBlockInfo(api.apiPb.blocks),
                };
            }
            return apiSemantics;
        }
        handleApiUpdate(api) {
            this.apiSemanticsByName[api.name] = {
                name: api.name,
                blocks: this.extractBlockInfo(api.apiPb.blocks),
            };
        }
        handleApiDelete(apiName) {
            delete this.apiSemanticsByName[apiName];
        }
        traverseWidgetTree(rootNodes, basePath, pageName) {
            const semantics = [];
            const processSiblings = (siblings, path) => {
                if (!siblings) {
                    return;
                }
                const tagNameCounts = {};
                for (const node of siblings) {
                    if (isWidgetNode(node) || isHTMLElementNode(node)) {
                        tagNameCounts[node.tagName] = (tagNameCounts[node.tagName] ?? 0) + 1;
                    }
                }
                const tagNameRunningCounts = {};
                for (const node of siblings) {
                    traverse(node, path, tagNameCounts, tagNameRunningCounts);
                }
            };
            const traverse = (node, parentPath, siblingTagCounts, siblingTagRunningCounts) => {
                let currentPath = parentPath;
                let nthOfType = 0;
                if (isWidgetNode(node) || isHTMLElementNode(node)) {
                    const totalOfType = siblingTagCounts[node.tagName] ?? 1;
                    const runningCount = (siblingTagRunningCounts[node.tagName] ?? 0) + 1;
                    siblingTagRunningCounts[node.tagName] = runningCount;
                    nthOfType = runningCount;
                    let pathSegment = node.tagName;
                    if (totalOfType > 1) {
                        pathSegment = `${node.tagName}[${nthOfType}]`;
                    }
                    currentPath = [...parentPath, pathSegment];
                    const semanticPath = currentPath.join(" > ");
                    const elementId = node.id;
                    let location;
                    try {
                        if (this.fileSystemInterface) {
                            location =
                                this.fileSystemInterface.getElementToLocation(elementId)?.node
                                    ?.loc;
                        }
                    }
                    catch {
                        // no-op
                    }
                    const info = {
                        id: elementId,
                        tagName: node.tagName,
                        location,
                        bindName: node.name === node.tagName ? undefined : node.name,
                        semanticPath,
                        semanticProperties: this.extractSemanticProperties(node.properties),
                        nthOfType,
                        isCustomComponent: ComponentsManager.getInstance().isCustomComponent(node.tagName),
                        pageName,
                    };
                    semantics.push(info);
                }
                if ("children" in node && node.children) {
                    processSiblings(node.children, currentPath);
                }
            };
            processSiblings(rootNodes, basePath);
            return semantics;
        }
        traversePageWidgets(pages) {
            const allSemantics = [];
            for (const page of Object.values(pages)) {
                const rootNodes = page.roots.map((r) => r.root);
                const pageSemantics = this.traverseWidgetTree(rootNodes, [page.name], page.name);
                allSemantics.push(...pageSemantics);
            }
            return allSemantics;
        }
        traverseAppWidgets(appRoots = []) {
            const rootNodes = appRoots.map((r) => r.root);
            return this.traverseWidgetTree(rootNodes, ["App"], "App");
        }
        handleAppScopeReset(appScope) {
            this.appScopeId = appScope.scopeId;
            // Track page names
            this.pageNames = new Set(Object.keys(appScope.pages));
            // Process both page-level and app-level components
            const pageComponents = this.traversePageWidgets(appScope.pages);
            const appComponents = this.traverseAppWidgets(appScope.roots);
            this.componentSemanticsById = Object.fromEntries([...pageComponents, ...appComponents].map((widgetInfo) => [
                widgetInfo.id,
                widgetInfo,
            ]));
            this.apiSemanticsByName = this.extractApiSemantics(appScope.apis);
        }
        getComponentsForApp() {
            return Object.values(this.componentSemanticsById).filter((component) => component.pageName === "App");
        }
        isEssentiallyBlank() {
            const nonDivComponents = Object.values(this.componentSemanticsById).filter((component) => component.tagName !== "div");
            return (nonDivComponents.length === 0 &&
                Object.keys(this.apiSemanticsByName).length === 0);
        }
        /**
         * Get all page names in the application
         */
        getPageNames() {
            return Array.from(this.pageNames).sort();
        }
        /**
         * Get all components for a specific page
         */
        getComponentsForPage(pageName) {
            return Object.values(this.componentSemanticsById).filter((component) => component.pageName === pageName);
        }
        getComponent(componentId) {
            return this.componentSemanticsById[componentId];
        }
        /**
         * Get the page name for a specific component
         */
        getPageForComponent(componentId) {
            return this.componentSemanticsById[componentId]?.pageName;
        }
        /**
         * Check if a specific page is essentially blank (has no meaningful components)
         */
        isPageEssentiallyBlank(pageName) {
            const pageComponents = this.getComponentsForPage(pageName).filter((component) => component.tagName !== "div");
            return pageComponents.length === 0;
        }
        /**
         * Get component count by page
         */
        getComponentCountByPage() {
            const counts = {};
            for (const pageName of this.pageNames) {
                counts[pageName] = this.getComponentsForPage(pageName).filter((component) => component.tagName !== NATIVE_COMPONENT_TYPES.Page &&
                    component.tagName !== NATIVE_COMPONENT_TYPES.Section &&
                    component.tagName !== NATIVE_COMPONENT_TYPES.Column &&
                    component.tagName !== "Container").length;
            }
            return counts;
        }
        /**
         * Check if the application has multiple pages
         */
        hasMultiplePages() {
            return this.pageNames.size > 1;
        }
        /**
         * Get all APIs for a specific page
         */
        getApisForPage(pageName) {
            return Object.values(this.apiSemanticsByName).filter((api) => api.pageName === pageName);
        }
    };
})();
export { AppContextStore };
//# sourceMappingURL=app-context.js.map