import { SchemaBuildError } from '@takeshape/errors';
import { deepClone } from '@takeshape/util';
import isError from 'lodash/isError.js';
import set from 'lodash/set.js';
import { addAiQueries } from "./agents.js";
import { flattenTemplates } from "./flatten-templates.js";
import { addRelatedFields, findExistingRelationships } from "./relationships.js";
import { ASSET_SHAPE_NAME } from "./resolvers/takeshape/assets/constants.js";
import { applyDefaultsToSchema, createShape } from "./schema-util.js";
import { resolveSchemaShapeDependencies } from "./service-dependencies.js";
import { isModelShape } from "./types/index.js";
export function applyLegacyCompatibilityTweaks(projectSchema) {
    const newSchema = deepClone(projectSchema);
    let hasSearchableShapes = false;
    for (const [shapeName, shape] of Object.entries(newSchema.shapes)) {
        if (isModelShape(shape)) {
            hasSearchableShapes = true;
            // Magic _contentTypeId field used for V1 compatibility
            set(shape, ['schema', 'properties', '_contentTypeId'], {
                type: 'string'
            });
            set(shape, ['schema', 'properties', '_contentTypeName'], {
                type: 'string'
            });
            if (shape.model?.type !== 'single') {
                newSchema.queries[`search${shapeName}Index`] = {
                    shape: `SearchResults<${shapeName}>`,
                    resolver: {
                        name: 'takeshape:search',
                        service: 'takeshape',
                        shapeName
                    },
                    args: `TSSearchArgs<${shapeName}>`
                };
            }
        }
        if (shapeName === ASSET_SHAPE_NAME) {
            // Magic s3Key field to provide V1 compatibility with old projects until the field is
            // formally removed and users are notified
            set(shape, ['schema', 'properties', 's3Key'], {
                title: 's3 key',
                type: 'string',
                '@mapping': 'shapedb:Asset.Hk6FQuz5',
                '@deprecationReason': 'Use path instead'
            });
        }
    }
    if (hasSearchableShapes) {
        // A placeholder shape for the TSSearchable interface
        newSchema.shapes.TSSearchable = createShape('TSSearchable', {
            type: 'object',
            properties: {}
        });
        newSchema.queries.search = {
            shape: 'SearchResults<TSSearchable>',
            resolver: {
                name: 'takeshape:search',
                service: 'takeshape'
            },
            args: 'TSSearchArgs<TSSearchable>'
        };
    }
    addRelatedFields(newSchema, findExistingRelationships(projectSchema, projectSchema.shapes));
    return newSchema;
}
export function applyDefaultsAndFlatten(projectSchema, options) {
    let newSchema = projectSchema;
    newSchema = addAiQueries(newSchema);
    newSchema = applyDefaultsToSchema(newSchema, options);
    newSchema = applyLegacyCompatibilityTweaks(newSchema);
    newSchema = flattenTemplates(newSchema);
    return newSchema;
}
export function buildRuntimeSchema(projectSchema, serviceLayers, options) {
    try {
        const projectSchemaWithDependencies = resolveSchemaShapeDependencies(projectSchema, serviceLayers);
        return applyDefaultsAndFlatten(projectSchemaWithDependencies, options);
    }
    catch (err) {
        throw new SchemaBuildError('An error occurred while building the schema', {
            cause: isError(err) ? err : undefined,
            schema: projectSchema
        });
    }
}
