import { PageDecoration, PageMeta } from "$sb/types.ts";
import { SysCallMapping } from "$lib/plugos/system.ts";
import { Client } from "../client.ts";
import { parseTreeToAST } from "$sb/lib/tree.ts";
import { lezerToParseTree } from "$common/markdown_parser/parse_tree.ts";
import { expressionLanguage } from "$common/template/template_parser.ts";
import { expressionToKvQueryExpression } from "$sb/lib/parse-query.ts";
import { evalQueryExpression } from "$sb/lib/query_expression.ts";
import { builtinFunctions } from "$lib/builtin_query_functions.ts";

export function decorationSyscalls(
    client: Client,
): SysCallMapping {
    return {
        "decoration.applyDecorationsToPages": (
            _ctx,
            pages: PageMeta[],
        ): PageMeta[] => {
            if (client.settings.pageDecorations) {
                for (const pageMeta of pages) {
                    decoratePageMeta(pageMeta, client.settings.pageDecorations);
                }
            }
            return pages;
        },
    };
}

/**
 * Decorates (= attaches a pageDecoration field) to the pageMeta object when a matching decorator is found
 */
export function decoratePageMeta(
    pageMeta: PageMeta,
    decorations: PageDecoration[],
) {
    if (!pageMeta) {
        return;
    }
    for (const decoration of decorations) {
        if (!decoration.where) {
            continue;
        }
        // whereParsed is effectively a cached version of the parsed where expression
        // Let's check if it's populated
        if (!decoration.whereParsed) {
            // If not, populate it
            try {
                const ast = parseTreeToAST(lezerToParseTree(
                    decoration.where,
                    expressionLanguage.parser.parse(decoration.where).topNode,
                ));
                decoration.whereParsed = expressionToKvQueryExpression(
                    ast[1],
                );
            } catch (e: any) {
                console.error(
                    "Failed to parse 'where' expression in decoration:",
                    e,
                );
                continue;
            }
        }
        if (
            evalQueryExpression(
                decoration.whereParsed,
                pageMeta,
                {},
                builtinFunctions,
            )
        ) {
            pageMeta.pageDecoration = decoration;
        }
    }
}