import { DomainEntityKind } from '../../models/kinds.js';
import { DataSemantics, isPropertySemantic, SemanticType } from '../Semantics.js';
/**
 * SemanticValidation is a class that performs validation on semantics in a data domain.
 * It checks for required and recommended semantics in entities, properties, and associations.
 */
export class SemanticValidation {
    domain;
    constructor(domain) {
        this.domain = domain;
    }
    /**
     * Performs all the semantic validation rules on the domain.
     * @returns The list of validation messages.
     */
    validate() {
        const results = [];
        // Check for User entity semantic
        const hasUserEntity = this.validateUserEntity();
        results.push(...hasUserEntity);
        // Check for timestamp semantics
        const timestampSemantics = this.validateTimestampSemantics();
        results.push(...timestampSemantics);
        // Check for soft delete semantics
        const softDeleteSemantics = this.validateSoftDeleteSemantics();
        results.push(...softDeleteSemantics);
        // Validate property semantics data types
        const propertySemanticsDataTypes = this.validatePropertySemanticsDataTypes();
        results.push(...propertySemanticsDataTypes);
        return results;
    }
    /**
     * Validates if there is at least one entity with the User semantic.
     * This is a recommended semantic for authentication purposes.
     */
    validateUserEntity() {
        const results = [];
        let hasUserEntity = false;
        for (const entity of this.domain.listEntities()) {
            if (entity.hasSemantic(SemanticType.User)) {
                hasUserEntity = true;
                break;
            }
        }
        if (!hasUserEntity) {
            results.push({
                field: 'semantics',
                rule: 'recommended',
                message: 'No entity with User taxonomy found in the domain.',
                help: 'It is recommended to have at least one entity with the User taxonomy for authentication purposes.',
                severity: 'warning',
                key: 'user_semantic',
                kind: DomainEntityKind,
            });
        }
        return results;
    }
    /**
     * Validates if entities have the recommended timestamp semantics.
     * This includes CreatedTimestamp and UpdatedTimestamp.
     */
    validateTimestampSemantics() {
        const results = [];
        for (const entity of this.domain.listEntities()) {
            let hasCreatedTimestamp = false;
            let hasUpdatedTimestamp = false;
            for (const property of entity.listProperties()) {
                if (property.hasSemantic(SemanticType.CreatedTimestamp)) {
                    hasCreatedTimestamp = true;
                }
                if (property.hasSemantic(SemanticType.UpdatedTimestamp)) {
                    hasUpdatedTimestamp = true;
                }
            }
            if (!hasCreatedTimestamp) {
                results.push({
                    field: 'semantics',
                    rule: 'recommended',
                    message: `The "${entity.info.getLabel()}" entity does not have a CreatedTimestamp taxonomy.`,
                    help: 'It is recommended to have a CreatedTimestamp property to track when the entity was created.',
                    severity: 'info',
                    key: entity.key,
                    kind: entity.kind,
                });
            }
            if (!hasUpdatedTimestamp) {
                results.push({
                    field: 'semantics',
                    rule: 'recommended',
                    message: `The "${entity.info.getLabel()}" entity does not have an UpdatedTimestamp taxonomy.`,
                    help: 'It is recommended to have an UpdatedTimestamp property to track when the entity was last modified.',
                    severity: 'info',
                    key: entity.key,
                    kind: entity.kind,
                });
            }
        }
        return results;
    }
    /**
     * Validates if entities have the recommended soft delete semantics.
     * This includes either DeletedTimestamp or DeletedFlag.
     */
    validateSoftDeleteSemantics() {
        const results = [];
        for (const entity of this.domain.listEntities()) {
            let hasSoftDelete = false;
            for (const property of entity.listProperties()) {
                if (property.hasSemantic(SemanticType.DeletedTimestamp) || property.hasSemantic(SemanticType.DeletedFlag)) {
                    hasSoftDelete = true;
                    break;
                }
            }
            if (!hasSoftDelete) {
                results.push({
                    field: 'semantics',
                    rule: 'recommended',
                    message: `The "${entity.info.getLabel()}" entity does not have soft delete taxonomy.`,
                    help: 'It is recommended to have either a DeletedTimestamp or DeletedFlag property for soft deletion.',
                    severity: 'info',
                    key: entity.key,
                    kind: entity.kind,
                });
            }
        }
        return results;
    }
    /**
     * Validates if property semantics are applied to properties with compatible data types.
     */
    validatePropertySemanticsDataTypes() {
        const results = [];
        for (const entity of this.domain.listEntities()) {
            for (const property of entity.listProperties()) {
                for (const appliedSemantic of property.semantics) {
                    const semanticDefinition = DataSemantics[appliedSemantic.id];
                    if (isPropertySemantic(semanticDefinition) && semanticDefinition.applicableDataTypes) {
                        if (!semanticDefinition.applicableDataTypes.includes(property.type)) {
                            results.push({
                                field: 'semantics',
                                rule: 'type_mismatch',
                                message: `The "${property.info.getLabel()}" property has the "${semanticDefinition.displayName}" semantic applied, but its type "${property.type}" is not compatible.`,
                                help: `The "${semanticDefinition.displayName}" semantic can only be applied to properties of type(s): ${semanticDefinition.applicableDataTypes.join(', ')}.`,
                                severity: 'error',
                                key: property.key,
                                kind: property.kind,
                                parent: entity.key,
                            });
                        }
                    }
                }
            }
        }
        return results;
    }
}
//# sourceMappingURL=semantic_validation.js.map