import { parseBooleanValue } from '../domain/types.js';
const VALID_TYPES = [
    'id',
    'varchar',
    'char',
    'text',
    'int',
    'bigint',
    'smallint',
    'decimal',
    'float',
    'boolean',
    'date',
    'timestamp',
    'json',
    'jsonb',
    'enum',
    'array',
    'relationship',
    'blob',
    'password',
    'manyToMany',
];
const VALID_INDEX_TYPES = ['index', 'unique'];
const CAMEL_CASE_REGEX = /^[a-z][a-zA-Z0-9]*$/;
export function validateSchema(schema) {
    const errors = [];
    const warnings = [];
    if (!schema.moduleName) {
        errors.push({
            field: 'moduleName',
            message: 'Module name is required',
            severity: 'error',
        });
    }
    else if (!CAMEL_CASE_REGEX.test(schema.moduleName)) {
        warnings.push({
            field: 'moduleName',
            message: `Module name "${schema.moduleName}" should be camelCase`,
            severity: 'warning',
        });
    }
    if (!schema.aggregateName) {
        errors.push({
            field: 'aggregateName',
            message: 'Aggregate name is required',
            severity: 'error',
        });
    }
    if (!schema.boundedContextName) {
        errors.push({
            field: 'boundedContextName',
            message: 'Bounded context name is required',
            severity: 'error',
        });
    }
    if (!schema.aggregateProperties || schema.aggregateProperties.length === 0) {
        errors.push({
            field: 'aggregateProperties',
            message: 'At least one property is required',
            severity: 'error',
        });
    }
    else {
        const propertyMap = new Map();
        let hasPrimaryKey = false;
        for (const prop of schema.aggregateProperties) {
            const propErrors = validateProperty(prop, propertyMap);
            errors.push(...propErrors.filter((e) => e.severity === 'error'));
            warnings.push(...propErrors.filter((e) => e.severity === 'warning'));
            if (prop.primaryKey)
                hasPrimaryKey = true;
            propertyMap.set(prop.name, prop.isI18n ?? false);
        }
        if (!hasPrimaryKey) {
            errors.push({
                field: 'aggregateProperties',
                message: 'At least one primary key is required',
                severity: 'error',
            });
        }
    }
    return {
        errors,
        isValid: errors.length === 0,
        warnings,
    };
}
export function validateProperty(prop, existingProperties) {
    const errors = [];
    if (prop.name) {
        if (!CAMEL_CASE_REGEX.test(prop.name)) {
            errors.push({
                field: `property.${prop.name}`,
                message: `Property name "${prop.name}" should be camelCase`,
                severity: 'warning',
            });
        }
        if (existingProperties?.has(prop.name)) {
            const existingIsI18n = existingProperties.get(prop.name);
            const currentIsI18n = prop.isI18n ?? false;
            if (existingIsI18n === currentIsI18n) {
                errors.push({
                    field: `property.${prop.name}`,
                    message: `Duplicate property name "${prop.name}"`,
                    severity: 'error',
                });
            }
        }
    }
    else {
        errors.push({
            field: 'property',
            message: 'Property name is required',
            severity: 'error',
        });
    }
    if (!prop.type) {
        errors.push({
            field: `property.${prop.name}.type`,
            message: 'Property type is required',
            severity: 'error',
        });
    }
    else if (!VALID_TYPES.includes(prop.type)) {
        errors.push({
            field: `property.${prop.name}.type`,
            message: `Invalid type "${prop.type}". Valid types: ${VALID_TYPES.join(', ')}`,
            severity: 'error',
        });
    }
    if (prop.type === 'enum' &&
        (!prop.enumOptions || prop.enumOptions.length === 0)) {
        errors.push({
            field: `property.${prop.name}.enumOptions`,
            message: 'Enum type requires enumOptions',
            severity: 'error',
        });
    }
    if (prop.type === 'array' && !prop.arrayOptions?.type) {
        errors.push({
            field: `property.${prop.name}.arrayOptions`,
            message: 'Array type requires arrayOptions.type',
            severity: 'error',
        });
    }
    if (prop.type === 'varchar' && !prop.maxLength) {
        errors.push({
            field: `property.${prop.name}.maxLength`,
            message: 'Varchar type should specify maxLength',
            severity: 'warning',
        });
    }
    if (prop.type === 'decimal' && !prop.decimals) {
        errors.push({
            field: `property.${prop.name}.decimals`,
            message: 'Decimal type should specify decimals [precision, scale]',
            severity: 'warning',
        });
    }
    if (prop.index && !VALID_INDEX_TYPES.includes(prop.index)) {
        errors.push({
            field: `property.${prop.name}.index`,
            message: `Invalid index type "${prop.index}". Valid: ${VALID_INDEX_TYPES.join(', ')}`,
            severity: 'error',
        });
    }
    if (prop.type === 'relationship' && !prop.relationship) {
        errors.push({
            field: `property.${prop.name}.relationship`,
            message: 'Relationship type requires relationship configuration',
            severity: 'error',
        });
    }
    if (prop.relationship) {
        if (!prop.relationship.type) {
            errors.push({
                field: `property.${prop.name}.relationship.type`,
                message: 'Relationship type is required',
                severity: 'error',
            });
        }
        if (!prop.relationship.aggregateName) {
            errors.push({
                field: `property.${prop.name}.relationship.aggregateName`,
                message: 'Relationship aggregateName is required',
                severity: 'error',
            });
        }
        if (!prop.relationship.modulePath) {
            errors.push({
                field: `property.${prop.name}.relationship.modulePath`,
                message: 'Relationship modulePath is required',
                severity: 'error',
            });
        }
    }
    return errors;
}
export function validateSheetData(data) {
    const errors = [];
    const warnings = [];
    if (!data.metadata.moduleName) {
        errors.push({
            field: 'metadata.moduleName',
            message: 'Module name is required in sheet',
            severity: 'error',
        });
    }
    if (!data.metadata.aggregateName) {
        errors.push({
            field: 'metadata.aggregateName',
            message: 'Aggregate name is required in sheet',
            severity: 'error',
        });
    }
    if (data.properties.length === 0) {
        errors.push({
            field: 'properties',
            message: 'At least one property row is required',
            severity: 'error',
        });
    }
    else {
        const propertyMap = new Map();
        for (const row of data.properties) {
            const rowErrors = validatePropertyRow(row, propertyMap);
            errors.push(...rowErrors.filter((e) => e.severity === 'error'));
            warnings.push(...rowErrors.filter((e) => e.severity === 'warning'));
            if (row.name)
                propertyMap.set(row.name, parseBooleanValue(row.isI18n));
        }
    }
    return {
        errors,
        isValid: errors.length === 0,
        warnings,
    };
}
export function validatePropertyRow(row, existingProperties) {
    const errors = [];
    if (!row.name) {
        errors.push({
            field: 'row',
            message: 'Property name is required',
            severity: 'error',
        });
        return errors;
    }
    if (!CAMEL_CASE_REGEX.test(row.name)) {
        errors.push({
            field: `row.${row.name}`,
            message: `Property name "${row.name}" should be camelCase`,
            severity: 'warning',
        });
    }
    if (existingProperties?.has(row.name)) {
        const existingIsI18n = existingProperties.get(row.name);
        const currentIsI18n = parseBooleanValue(row.isI18n);
        if (existingIsI18n === currentIsI18n) {
            errors.push({
                field: `row.${row.name}`,
                message: `Duplicate property name "${row.name}"`,
                severity: 'error',
            });
        }
    }
    if (!row.type) {
        errors.push({
            field: `row.${row.name}.type`,
            message: 'Type is required',
            severity: 'error',
        });
    }
    else if (!VALID_TYPES.includes(row.type)) {
        errors.push({
            field: `row.${row.name}.type`,
            message: `Invalid type "${row.type}"`,
            severity: 'error',
        });
    }
    if (row.type === 'enum' && !row.enumOptions) {
        errors.push({
            field: `row.${row.name}.enumOptions`,
            message: 'Enum requires enumOptions',
            severity: 'error',
        });
    }
    if (row.type === 'array' && !row['arrayOptions.type']) {
        errors.push({
            field: `row.${row.name}.arrayOptions`,
            message: 'Array requires arrayOptions.type',
            severity: 'error',
        });
    }
    return errors;
}
export function formatValidationResult(result) {
    const lines = [];
    if (result.isValid) {
        lines.push('Validation passed');
    }
    else {
        lines.push('Validation failed');
    }
    if (result.errors.length > 0) {
        lines.push('\nErrors:');
        for (const err of result.errors) {
            lines.push(`  ${err.field}: ${err.message}`);
        }
    }
    if (result.warnings.length > 0) {
        lines.push('\nWarnings:');
        for (const warn of result.warnings) {
            lines.push(`  ${warn.field}: ${warn.message}`);
        }
    }
    return lines.join('\n');
}
