/**
 * Get normalized properties for a limetype
 * Adds system properties (_id, _timestamp, etc.) that map to the actual limeobject attributes
 * @param limetype The limetype to normalize
 * @returns Normalized properties with system properties prefixed with underscore
 */
export function getNormalizedProperties(limetype) {
    if (!(limetype === null || limetype === void 0 ? void 0 : limetype.properties)) {
        return {};
    }
    const properties = Object.assign({}, limetype.properties);
    // System properties that are exposed by the backend
    // Map from internal property name to API property name
    const systemProperties = {
        id: '_id',
        timestamp: '_timestamp',
        descriptive: '_descriptive',
        createduser: '_createduser',
        createdtime: '_createdtime',
        updateduser: '_updateduser',
    };
    // Find and normalize system properties by name
    for (const [propName, systemPropName] of Object.entries(systemProperties)) {
        const property = properties[propName];
        if (property) {
            properties[systemPropName] = property;
            delete properties[propName];
        }
    }
    return properties;
}
/**
 * Get property from limetype by path (e.g., "company.name")
 * Supports relation traversal with dot-notation
 * @param limetypes
 * @param limetype
 * @param path
 */
export function getPropertyFromPath(limetypes, limetype, path) {
    if (!path || !limetype || !limetypes) {
        return undefined;
    }
    const parts = path.split('.');
    let currentType = limetypes[limetype];
    let property;
    for (const part of parts) {
        if (!currentType) {
            return undefined;
        }
        const normalizedProperties = getNormalizedProperties(currentType);
        property = normalizedProperties[part];
        if (!property) {
            return undefined;
        }
        // If this is a relation, get the related limetype for next iteration
        if (property.relation) {
            currentType = property.relation.getLimetype();
        }
    }
    return property;
}
/**
 * Validates a property path to ensure no intermediate properties are hasMany or hasAndBelongsToMany relations.
 * These relation types cannot be traversed in filter expressions.
 * @param limetypes All limetype definitions
 * @param limetype The starting limetype
 * @param path The property path to validate (e.g., "company.name")
 * @returns The property at the end of the path if valid, or undefined with error if invalid
 */
export function validatePropertyPath(limetypes, limetype, path) {
    if (!path || !limetype || !limetypes) {
        return { property: undefined };
    }
    const parts = path.split('.');
    let currentType = limetypes[limetype];
    let property;
    for (let i = 0; i < parts.length; i++) {
        const part = parts[i];
        if (!currentType) {
            return { property: undefined };
        }
        const normalizedProperties = getNormalizedProperties(currentType);
        property = normalizedProperties[part];
        if (!property) {
            return {
                property: undefined,
                error: `Property '${part}' does not exist on limetype '${currentType.name}'`,
            };
        }
        // Check if this property is a hasMany/hasAndBelongsToMany relation
        // These cannot be traversed in filter expressions
        if (property.type === 'hasmany' ||
            property.type === 'hasandbelongstomany') {
            // Build the path up to this point for the error message
            const invalidPath = parts.slice(0, i + 1).join('.');
            return {
                property: undefined,
                error: `Cannot filter on many-relation '${invalidPath}'. Use a related limetype's filter instead.`,
            };
        }
        // If this is a relation, get the related limetype for next iteration
        if (property.relation) {
            currentType = property.relation.getLimetype();
        }
    }
    return { property };
}
