import * as t from "@babel/types";
import JSON5 from "json5";
import { isPropertyInfo, Property } from "@superblocksteam/library-shared";
import { parsingRegistry } from "./parsing/type-parsing-registry.js";
import { stringToTaggedTemplate, parseExpression, canBeAStringLiteral, createObjectKey, } from "./parsing/util.js";
import { getErrorMeta, getLogger } from "./util/logger.js";
export function generateJSXAttribute(name, info) {
    const valueNode = getPropertyExpression(info, name);
    if (t.isStringLiteral(valueNode)) {
        return t.jsxAttribute(t.jsxIdentifier(name), valueNode);
    }
    else {
        return t.jsxAttribute(t.jsxIdentifier(name), t.jsxExpressionContainer(valueNode));
    }
}
export function getPropertyExpression(info, fieldName = "") {
    const logger = getLogger();
    const { value, type } = info;
    try {
        if (type === "BINDING") {
            const cleanedValue = typeof value === "string" ? value.replaceAll("${", "\\${") : value;
            return stringToTaggedTemplate(cleanedValue);
        }
        else if (type === "TEMPLATE") {
            try {
                const code = parsingRegistry.TEMPLATE.toCode(value, info);
                const expression = parseExpression(code);
                if (expression) {
                    return expression;
                }
                else {
                    return t.stringLiteral(code);
                }
            }
            catch {
                const safeString = safelyEncodeTemplateProperty(value);
                return t.templateLiteral([
                    t.templateElement({
                        raw: safeString,
                        cooked: safeString,
                    }, true),
                ], []);
            }
        }
        else if (type === "DIMENSION") {
            const code = parsingRegistry.DIMENSION.toCode(value, info);
            const expression = parseExpression(code);
            if (expression) {
                return expression;
            }
            else {
                return t.stringLiteral(code);
            }
        }
        if (type === "EXPRESSION" && typeof value === "string") {
            const expression = parseExpression(value);
            if (expression) {
                return expression;
            }
            else {
                return t.stringLiteral(value);
            }
        }
        else if (type === "FUNCTION" && typeof value === "string") {
            const code = parsingRegistry.FUNCTION.toCode(value, info);
            const expression = parseExpression(code);
            if (expression) {
                return expression;
            }
            else {
                return t.stringLiteral(value);
            }
        }
        else if (type === "COMPUTED" && typeof value === "string") {
            let parsed;
            try {
                parsed = JSON5.parse(value);
                return getPropertyExpression(Property.Static(parsed), fieldName);
            }
            catch (_e) {
                // do nothing
            }
            // if we can parse the value as json then its not a computed value so no need to
            // parse it as such
            if (parsed === undefined) {
                try {
                    const code = parsingRegistry.COMPUTED.toCode(value, info);
                    const computedExpression = parseExpression(code);
                    if (computedExpression) {
                        return computedExpression;
                    }
                }
                catch (e) {
                    getLogger().error("could not generate computed expression", getErrorMeta(e));
                }
                const fallbackLiteral = t.templateLiteral([t.templateElement({ raw: value, cooked: value }, true)], []);
                fallbackLiteral.extra = {
                    computedFallback: true,
                    error: "Could not generate computed expression",
                };
                return fallbackLiteral;
            }
        }
        if (Array.isArray(value)) {
            const arrayElements = value.map((v) => {
                const propertyInfo = isPropertyInfo(v) ? v : Property.Any(v);
                return getPropertyExpression(propertyInfo, fieldName);
            });
            return t.arrayExpression(arrayElements);
        }
        if (typeof value === "object" && value !== null) {
            return t.objectExpression(Object.entries(value).map(([key, value]) => {
                let objectValue;
                if (isPropertyInfo(value)) {
                    objectValue = getPropertyExpression(value, key);
                }
                else if (Array.isArray(value)) {
                    objectValue = getPropertyExpression(Property.Any(value), key);
                }
                else if (typeof value === "object" && value !== null) {
                    objectValue = getPropertyExpression(Property.Any(value), key);
                }
                else {
                    objectValue = t.valueToNode(value);
                }
                return t.objectProperty(createObjectKey(key), objectValue);
            }));
        }
        if (typeof value === "number") {
            return t.numericLiteral(value);
        }
        if (typeof value === "boolean") {
            return t.booleanLiteral(value);
        }
        if (typeof value === "string") {
            if (canBeAStringLiteral(value)) {
                return t.stringLiteral(value);
            }
            else {
                return t.templateLiteral([t.templateElement({ raw: value, cooked: value }, true)], []);
            }
        }
        if (typeof value === "object" || value === undefined) {
            return t.valueToNode(value);
        }
        logger.warn(`Unsupported value type: ${value} ${type}`);
        return t.stringLiteral(String(value));
    }
    catch (e) {
        logger.error(`Error generating code value: ${JSON.stringify(value)} ${type}`, getErrorMeta(e));
        return t.stringLiteral(String(value));
    }
}
function safelyEncodeTemplateProperty(value) {
    return value.replace(/\${/g, "\\${");
}
//# sourceMappingURL=codegen.js.map