import GraphModelMigrationBasis from "./GraphModelMigrationBasis.js";
import GraphModelMigrationContentMapping from "./GraphModelMigrationContentMapping.js";
import GraphModelMigrationEdgeMapping from "./GraphModelMigrationEdgeMapping.js";
import GraphModelMigrationManifestVersion from "./GraphModelMigrationManifestVersion.js";
import GraphModelMigrationNodeMapping from "./GraphModelMigrationNodeMapping.js";
import GraphModelMigrationNotice from "./GraphModelMigrationNotice.js";
import GraphModelMigrationPropertyMapping from "./GraphModelMigrationPropertyMapping.js";
import WarpError from "../errors/WarpError.js";
/** Runtime-backed root manifest for a dry-run graph-model migration plan. */
export default class GraphModelMigrationManifest {
    version;
    sourceBasis;
    targetBasis;
    nodeMappings;
    edgeMappings;
    propertyMappings;
    contentMappings;
    warnings;
    fatalErrors;
    constructor(fields) {
        const checkedFields = requireFields(fields);
        this.version = requireVersion(checkedFields.version);
        this.sourceBasis = requireBasis(checkedFields.sourceBasis, 'sourceBasis');
        this.targetBasis = requireBasis(checkedFields.targetBasis, 'targetBasis');
        this.nodeMappings = freezeNodeMappings(checkedFields.nodeMappings);
        this.edgeMappings = freezeEdgeMappings(checkedFields.edgeMappings);
        this.propertyMappings = freezePropertyMappings(checkedFields.propertyMappings);
        this.contentMappings = freezeContentMappings(checkedFields.contentMappings);
        this.warnings = freezeWarningNotices(checkedFields.warnings);
        this.fatalErrors = freezeFatalNotices(checkedFields.fatalErrors);
        Object.freeze(this);
    }
    /** Returns true when the manifest contains fatal planning failures. */
    hasFatalErrors() {
        return this.fatalErrors.length > 0;
    }
}
/** Validates the constructor envelope. */
function requireFields(fields) {
    if (fields === null || fields === undefined) {
        throw new WarpError('GraphModelMigrationManifest fields must be provided', 'E_VALIDATION');
    }
    return fields;
}
/** Requires a runtime-backed manifest version. */
function requireVersion(version) {
    if (!(version instanceof GraphModelMigrationManifestVersion)) {
        throw new WarpError('GraphModelMigrationManifest version must be a GraphModelMigrationManifestVersion', 'E_VALIDATION');
    }
    return version;
}
/** Requires a runtime-backed migration basis. */
function requireBasis(basis, name) {
    if (!(basis instanceof GraphModelMigrationBasis)) {
        throw new WarpError(`${name} must be a GraphModelMigrationBasis`, 'E_VALIDATION');
    }
    return basis;
}
/** Validates and freezes node mappings. */
function freezeNodeMappings(mappings) {
    const checked = requireArray(mappings, 'nodeMappings').map(requireNodeMapping);
    requireUnique(checked.map((mapping) => mapping.legacyNodeId), 'legacy node mapping');
    return Object.freeze(checked);
}
/** Validates and freezes edge mappings. */
function freezeEdgeMappings(mappings) {
    const checked = requireArray(mappings, 'edgeMappings').map(requireEdgeMapping);
    requireUnique(checked.map((mapping) => mapping.legacyEdgeId), 'legacy edge mapping');
    return Object.freeze(checked);
}
/** Validates and freezes property mappings. */
function freezePropertyMappings(mappings) {
    const checked = requireArray(mappings, 'propertyMappings').map(requirePropertyMapping);
    requireUnique(checked.map((mapping) => mapping.legacyKey()), 'legacy property mapping');
    return Object.freeze(checked);
}
/** Validates and freezes content mappings. */
function freezeContentMappings(mappings) {
    const checked = requireArray(mappings, 'contentMappings').map(requireContentMapping);
    requireUnique(checked.map((mapping) => mapping.legacyContentKey), 'legacy content mapping');
    return Object.freeze(checked);
}
/** Validates and freezes warning notices. */
function freezeWarningNotices(notices) {
    const checked = requireArray(notices, 'warnings').map(requireNotice);
    for (const notice of checked) {
        if (notice.isFatal()) {
            throw new WarpError('warnings contains the wrong notice kind', 'E_VALIDATION');
        }
    }
    return Object.freeze(checked);
}
/** Validates and freezes fatal notices. */
function freezeFatalNotices(notices) {
    const checked = requireArray(notices, 'fatalErrors').map(requireNotice);
    for (const notice of checked) {
        if (!notice.isFatal()) {
            throw new WarpError('fatalErrors contains the wrong notice kind', 'E_VALIDATION');
        }
    }
    return Object.freeze(checked);
}
/** Requires an array field. */
function requireArray(items, label) {
    if (items === null || items === undefined || !Array.isArray(items)) {
        throw new WarpError(`GraphModelMigrationManifest ${label} must be an array`, 'E_VALIDATION');
    }
    const checkedItems = items;
    return checkedItems;
}
/** Requires a node mapping instance. */
function requireNodeMapping(mapping) {
    if (!(mapping instanceof GraphModelMigrationNodeMapping)) {
        throw new WarpError('nodeMappings must contain node mappings', 'E_VALIDATION');
    }
    return mapping;
}
/** Requires an edge mapping instance. */
function requireEdgeMapping(mapping) {
    if (!(mapping instanceof GraphModelMigrationEdgeMapping)) {
        throw new WarpError('edgeMappings must contain edge mappings', 'E_VALIDATION');
    }
    return mapping;
}
/** Requires a property mapping instance. */
function requirePropertyMapping(mapping) {
    if (!(mapping instanceof GraphModelMigrationPropertyMapping)) {
        throw new WarpError('propertyMappings must contain property mappings', 'E_VALIDATION');
    }
    return mapping;
}
/** Requires a content mapping instance. */
function requireContentMapping(mapping) {
    if (!(mapping instanceof GraphModelMigrationContentMapping)) {
        throw new WarpError('contentMappings must contain content mappings', 'E_VALIDATION');
    }
    return mapping;
}
/** Requires a notice instance. */
function requireNotice(notice) {
    if (!(notice instanceof GraphModelMigrationNotice)) {
        throw new WarpError('migration notices must be GraphModelMigrationNotice instances', 'E_VALIDATION');
    }
    return notice;
}
/** Requires no duplicate keys in a manifest section. */
function requireUnique(keys, label) {
    const seen = new Set();
    for (const key of keys) {
        if (seen.has(key)) {
            throw new WarpError(`GraphModelMigrationManifest duplicates ${label} ${key}`, 'E_VALIDATION');
        }
        seen.add(key);
    }
}
