"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
var FieldMetadataService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.FieldMetadataService = void 0;
const string_helper_1 = require("../helpers/string.helper");
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const fs = __importStar(require("fs/promises"));
const module_metadata_helper_service_1 = require("../helpers/module-metadata-helper.service");
const solid_registry_1 = require("../helpers/solid-registry");
const field_metadata_repository_1 = require("../repository/field-metadata.repository");
const typeorm_2 = require("typeorm");
const create_field_metadata_dto_1 = require("../dtos/create-field-metadata.dto");
const model_metadata_entity_1 = require("../entities/model-metadata.entity");
const crud_helper_service_1 = require("./crud-helper.service");
const error_messages_1 = require("../constants/error-messages");
const qs_1 = __importDefault(require("qs"));
const media_storage_provider_metadata_repository_1 = require("../repository/media-storage-provider-metadata.repository");
const file_1 = require("./file");
let FieldMetadataService = FieldMetadataService_1 = class FieldMetadataService {
    constructor(fieldMetadataRepo, fileService, mediaStorageProviderMetadataRepository, dataSource, solidRegistry, crudHelperService, moduleMetadataHelperService) {
        this.fieldMetadataRepo = fieldMetadataRepo;
        this.fileService = fileService;
        this.mediaStorageProviderMetadataRepository = mediaStorageProviderMetadataRepository;
        this.dataSource = dataSource;
        this.solidRegistry = solidRegistry;
        this.crudHelperService = crudHelperService;
        this.moduleMetadataHelperService = moduleMetadataHelperService;
        this.logger = new common_1.Logger(FieldMetadataService_1.name);
    }
    onApplicationBootstrap() {
        this.loadAndRegisterComputedFieldsDetails();
    }
    async loadAndRegisterComputedFieldsDetails() {
        const computedFieldsWithModelAndModule = await this.fieldMetadataRepo.findComputedFieldsPopulatedWithModelAndModule();
        const computedFieldMetadata = computedFieldsWithModelAndModule.map((field) => {
            return {
                moduleName: field.model.module.name,
                modelName: field.model.singularName,
                fieldName: field.name,
                computedFieldValueType: field.computedFieldValueType,
                computedFieldTriggerConfig: field.computedFieldTriggerConfig ?? [],
                computedFieldValueProviderName: field.computedFieldValueProvider,
                computedFieldValueProviderCtxt: field.computedFieldValueProviderCtxt ? JSON.parse(field.computedFieldValueProviderCtxt) : {},
                eventContext: {}
            };
        });
        this.solidRegistry.registerComputedFieldMetadata(computedFieldMetadata);
    }
    async updateInverseField(field, fieldRepository, modelRepository) {
        if (!field.model || !field.model.module) {
            throw new Error(error_messages_1.ERROR_MESSAGES.MODEL_AND_MODULE_REQUIRED_TO_UPDATE_INVERSE_FIELD);
        }
        const savedInverseField = await this.updateInverseFieldInDb(field, fieldRepository, modelRepository);
        this.updateRelationInverseFieldInFile(savedInverseField, field.relationCoModelSingularName, field.model.module.name);
    }
    async updateInverseFieldInDb(field, fieldRepository, modelRepository) {
        const { moduleName, modelName } = this.validateForInverseField(field);
        const relationModel = await this.getRelationModel(modelRepository, field, moduleName);
        switch (field.relationType) {
            case create_field_metadata_dto_1.RelationType.manyToOne: {
                const fieldName = field.relationCoModelFieldName || `${modelName}s`;
                const inverseField = {
                    ...field,
                    name: fieldName,
                    displayName: (0, string_helper_1.classify)(fieldName),
                    description: (0, string_helper_1.classify)(fieldName),
                    type: create_field_metadata_dto_1.SolidFieldType.relation,
                    isSystem: field.isSystem,
                    relationType: create_field_metadata_dto_1.RelationType.oneToMany,
                    relationCoModelSingularName: modelName,
                    relationCreateInverse: true,
                    relationCascade: field.relationCascade,
                    relationModelModuleName: moduleName,
                    relationCoModelFieldName: field.name,
                    required: false,
                    unique: false,
                    index: false,
                    private: false,
                    encrypt: false,
                    model: relationModel,
                    columnName: null,
                    relationJoinTableName: null,
                    id: null,
                };
                const savedField = await this.saveInverseField(fieldRepository, relationModel, inverseField);
                return savedField;
            }
            case create_field_metadata_dto_1.RelationType.oneToMany: {
                const fieldName = field.relationCoModelFieldName || `${modelName}`;
                const inverseField = {
                    ...field,
                    name: fieldName,
                    displayName: (0, string_helper_1.classify)(fieldName),
                    description: (0, string_helper_1.classify)(fieldName),
                    type: create_field_metadata_dto_1.SolidFieldType.relation,
                    isSystem: field.isSystem,
                    relationType: create_field_metadata_dto_1.RelationType.manyToOne,
                    relationCoModelSingularName: modelName,
                    relationCreateInverse: true,
                    relationCascade: field.relationCascade,
                    relationModelModuleName: moduleName,
                    relationCoModelFieldName: field.name,
                    required: false,
                    unique: false,
                    index: false,
                    private: false,
                    encrypt: false,
                    model: relationModel,
                    columnName: null,
                    relationJoinTableName: null,
                    id: null,
                };
                const savedField = await this.saveInverseField(fieldRepository, relationModel, inverseField);
                return savedField;
            }
            case create_field_metadata_dto_1.RelationType.manyTomany: {
                const fieldName = field.relationCoModelFieldName;
                const inverseFieldManyToMany = {
                    ...field,
                    name: fieldName,
                    displayName: (0, string_helper_1.classify)(fieldName),
                    description: (0, string_helper_1.classify)(fieldName),
                    type: create_field_metadata_dto_1.SolidFieldType.relation,
                    isSystem: field.isSystem,
                    relationType: create_field_metadata_dto_1.RelationType.manyTomany,
                    relationCoModelSingularName: modelName,
                    relationCreateInverse: true,
                    relationCascade: null,
                    relationModelModuleName: moduleName,
                    relationCoModelFieldName: field.name,
                    required: false,
                    unique: false,
                    index: false,
                    private: false,
                    encrypt: false,
                    model: relationModel,
                    columnName: null,
                    relationJoinTableName: null,
                    isRelationManyToManyOwner: false,
                    id: null,
                };
                const savedField = await this.saveInverseField(fieldRepository, relationModel, inverseFieldManyToMany);
                return savedField;
            }
            default:
                throw new Error(`Invalid relation type for field ${field.name} with relation type  ${field.relationType}`);
        }
    }
    async getRelationModel(modelRepository, field, moduleName) {
        return await modelRepository.findOne({
            where: {
                singularName: field.relationCoModelSingularName,
                module: {
                    name: field.relationModelModuleName ?? moduleName
                }
            }
        });
    }
    async saveInverseField(fieldRepository, relationModel, inverseField) {
        const existingInverseField = await fieldRepository.findOne({
            where: {
                model: { id: relationModel.id },
                name: inverseField.name
            }
        });
        if (existingInverseField) {
            return existingInverseField;
        }
        else {
            const savedField = await fieldRepository.save(fieldRepository.create(inverseField));
            return savedField;
        }
    }
    validateForInverseField(field) {
        if (field.type !== create_field_metadata_dto_1.SolidFieldType.relation) {
            throw new Error(error_messages_1.ERROR_MESSAGES.INVALID_INVERSE_FIELD_TYPE);
        }
        const modelName = field.model.singularName;
        const moduleName = field.model.module.name;
        if (!modelName || !moduleName) {
            throw new Error(error_messages_1.ERROR_MESSAGES.MODEL_NAME_AND_MODULE_NAME_REQUIRED_TO_CREATE_INVERSE_FIELD);
        }
        return { moduleName, modelName };
    }
    async find(basicFilterDto) {
        return this.findMany(basicFilterDto);
    }
    async findMany(basicFilterDto) {
        const alias = 'fieldMetadata';
        let { limit, offset, populateMedia } = basicFilterDto;
        var qb = await this.fieldMetadataRepo.createSecurityRuleAwareQueryBuilder(alias);
        qb = await this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias);
        const [entities, count] = await qb.getManyAndCount();
        const currentPage = Math.floor(offset / limit) + 1;
        const totalPages = Math.ceil(count / limit);
        const nextPage = currentPage < totalPages ? currentPage + 1 : null;
        const prevPage = currentPage > 1 ? currentPage - 1 : null;
        const r = {
            meta: {
                totalRecords: count,
                currentPage: currentPage,
                nextPage: nextPage,
                prevPage: prevPage,
                totalPages: totalPages,
                perPage: +limit,
            },
            records: entities
        };
        return r;
    }
    async findOne(id, query) {
        const entity = await this.fieldMetadataRepo.findOne({
            where: {
                id: id,
            },
            relations: query && query?.populate,
        });
        if (!entity) {
            throw new common_1.NotFoundException(`entity #${id} not found`);
        }
        return entity;
    }
    async findByNameAndModelName(modelSingularName, fieldName) {
        const entity = await this.fieldMetadataRepo.findOne({
            where: {
                name: fieldName,
                model: {
                    singularName: modelSingularName
                }
            },
        });
        return entity;
    }
    async selectionStaticValues(modelSingularName, fieldName) {
        const entity = await this.fieldMetadataRepo.findOne({
            where: {
                name: fieldName,
                model: {
                    singularName: modelSingularName
                }
            },
        });
        if (!entity) {
            return [];
        }
        const selectionStaticValues = entity.selectionStaticValues;
        if (!selectionStaticValues) {
            return [];
        }
        return this.convertToSelectionProviderValues(selectionStaticValues);
    }
    convertToSelectionProviderValues(selectionStaticValues) {
        return selectionStaticValues.map((item) => {
            const [value, label] = item.split(':');
            return { label, value };
        });
    }
    async create(createDto) {
        createDto['model'] = await this.dataSource.getRepository(model_metadata_entity_1.ModelMetadata).findOne({
            where: {
                id: createDto['modelId']
            },
        });
        createDto['mediaStorageProvider'] = await this.dataSource.getRepository(model_metadata_entity_1.ModelMetadata).findOne({
            where: {
                id: createDto['mediaStorageProviderId']
            },
        });
        const moduleMetadata = this.fieldMetadataRepo.create(createDto);
        return this.fieldMetadataRepo.save(moduleMetadata);
    }
    async delete(id) {
        const entity = await this.findOne(id);
        return this.fieldMetadataRepo.remove(entity);
    }
    async findFieldDefaultMetaData() {
        const enumToResponseArray = (enumObj) => {
            return Object.entries(enumObj).map(([key, value]) => ({
                label: value,
                value: value,
            }));
        };
        const ormFieldTypeForSolid = this.getOrmFieldTypes();
        const dataSourceTypes = Object.keys(ormFieldTypeForSolid);
        const fieldTypes = Object.entries(ormFieldTypeForSolid.postgres).map(([key, value]) => ({
            type: key,
            label: key,
            value: key,
            fieldType: key,
            ormTypes: value.ormTypes,
            fields: this.fetchCurrentFields(key)
        }));
        const dataSource = this.solidRegistry.getSolidDatabaseModules().map((solidDatabaseModule) => {
            return {
                'name': solidDatabaseModule.instance.name(),
                'type': solidDatabaseModule.instance.type()
            };
        });
        const sps = [];
        const selectionProviders = this.solidRegistry.getSelectionProviders();
        for (let i = 0; i < selectionProviders.length; i++) {
            const selectionProvider = selectionProviders[i];
            sps.push({
                provider: selectionProvider.instance.name(),
                help: selectionProvider.instance.help(),
            });
        }
        const cps = [];
        const computedProviders = this.solidRegistry.getComputedFieldProviders();
        for (let i = 0; i < computedProviders.length; i++) {
            const computedProvider = computedProviders[i];
            cps.push({
                provider: computedProvider.instance.name(),
                help: computedProvider.instance.help(),
            });
        }
        const r = {
            fieldTypes: fieldTypes,
            encryptionTypes: enumToResponseArray(create_field_metadata_dto_1.EncryptionType),
            ormType: ormFieldTypeForSolid,
            decryptWhenTypes: enumToResponseArray(create_field_metadata_dto_1.DecryptWhenType),
            mediaTypes: enumToResponseArray(create_field_metadata_dto_1.MediaType),
            relationTypes: enumToResponseArray(create_field_metadata_dto_1.RelationType),
            selectionDynamicProviders: sps,
            computedProviders: cps,
            cascadeTypes: enumToResponseArray(create_field_metadata_dto_1.CascadeType),
            selectionValueTypes: enumToResponseArray(create_field_metadata_dto_1.SelectionValueType),
            computedFieldValueTypes: enumToResponseArray(create_field_metadata_dto_1.ComputedFieldValueType),
            dataSourceType: dataSourceTypes,
            dataSource: dataSource,
        };
        return r;
    }
    getOrmFieldTypes() {
        return {
            "postgres": {
                "int": {
                    "ormTypes": [{ label: create_field_metadata_dto_1.PSQLType.integer, description: "A 4-byte integer for general numeric data." }]
                },
                "bigint": {
                    "ormTypes": [{ label: create_field_metadata_dto_1.PSQLType.bigint, description: "An 8-byte integer for large numeric values." }]
                },
                "decimal": {
                    "ormTypes": [{ label: create_field_metadata_dto_1.PSQLType.decimal, description: "A high-precision numeric type, ideal for financial data." }]
                },
                "shortText": {
                    "ormTypes": [{ label: create_field_metadata_dto_1.PSQLType.varchar, description: "A variable-length string for short text." }]
                },
                "longText": {
                    "ormTypes": [{ label: create_field_metadata_dto_1.PSQLType.text, description: "A text type for large or unbounded strings." }]
                },
                "richText": {
                    "ormTypes": [{ label: create_field_metadata_dto_1.PSQLType.text, description: "A text type for large or formatted content." }]
                },
                "json": {
                    "ormTypes": [
                        { label: create_field_metadata_dto_1.MSSQLType.simplejson, description: "Creates DB agnostic column for storing json style data." },
                        { label: create_field_metadata_dto_1.PSQLType.json, description: "Stores JSON data without indexing." },
                        { label: create_field_metadata_dto_1.PSQLType.jsonb, description: "Stores JSON data with indexing for faster queries." }
                    ]
                },
                "boolean": {
                    "ormTypes": [{ label: create_field_metadata_dto_1.PSQLType.boolean, description: "Stores true or false values." }]
                },
                "date": {
                    "ormTypes": [{ label: create_field_metadata_dto_1.PSQLType.date, description: "Stores calendar dates (YYYY-MM-DD)." }]
                },
                "datetime": {
                    "ormTypes": [
                        { label: create_field_metadata_dto_1.PSQLType.timestamp, description: "Stores date and time without time zones." },
                        { label: create_field_metadata_dto_1.PSQLType.timestamptz, description: "Stores date and time with time zones." }
                    ]
                },
                "time": {
                    "ormTypes": [
                        { label: create_field_metadata_dto_1.PSQLType.time, description: "Stores time values (HH:MM:SS)." },
                        { label: create_field_metadata_dto_1.PSQLType.timestamp, description: "Stores date and time without time zones." },
                        { label: create_field_metadata_dto_1.PSQLType.timestamptz, description: "Stores date and time with time zones." }
                    ]
                },
                "relation": {
                    "ormTypes": [{ label: create_field_metadata_dto_1.PSQLType.integer, description: "Used for foreign keys referencing other entities." }]
                },
                "mediaSingle": {
                    "ormTypes": [{ label: create_field_metadata_dto_1.PSQLType.varchar, description: "Stores file paths or URLs for single media files." }]
                },
                "mediaMultiple": {
                    "ormTypes": [{ label: create_field_metadata_dto_1.PSQLType.varchar, description: "Stores file paths or URLs for multiple media files." }]
                },
                "email": {
                    "ormTypes": [{ label: create_field_metadata_dto_1.PSQLType.varchar, description: "Stores email addresses." }]
                },
                "password": {
                    "ormTypes": [{ label: create_field_metadata_dto_1.PSQLType.varchar, description: "Stores hashed or plain-text passwords." }]
                },
                "selectionStatic": {
                    "ormTypes": [{ label: create_field_metadata_dto_1.PSQLType.varchar, description: "Used for predefined selection options." }]
                },
                "selectionDynamic": {
                    "ormTypes": [{ label: create_field_metadata_dto_1.PSQLType.varchar, description: "Used for dynamic selection options." }]
                },
                "computed": {
                    "ormTypes": [{ label: create_field_metadata_dto_1.PSQLType.varchar, description: "Represents computed or derived fields." }]
                },
                "uuid": {
                    "ormTypes": [{ label: create_field_metadata_dto_1.PSQLType.varchar, description: "Stores universally unique identifiers (UUIDs)." }]
                }
            },
            "mssql": {
                "int": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.int, description: "A 4-byte integer for general numeric data." }
                    ]
                },
                "bigint": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.bigint, description: "An 8-byte integer for large numeric values." }
                    ]
                },
                "decimal": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.numeric, description: "A high-precision numeric type for financial or exact values." },
                        { label: create_field_metadata_dto_1.MSSQLType.decimal, description: "A high-precision decimal type for financial or exact values." }
                    ]
                },
                "shortText": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.varchar, description: "A variable-length string for short text." },
                        { label: create_field_metadata_dto_1.MSSQLType.nvarchar, description: "A unicode supported variable-length string for short text." }
                    ]
                },
                "longText": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.nvarchar, description: "A large or unbounded string type." }
                    ]
                },
                "richText": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.nvarchar, description: "A large text field for formatted or long content." }
                    ]
                },
                "json": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.simplejson, description: "Creates DB agnostic column for storing json style data." },
                        { label: create_field_metadata_dto_1.MSSQLType.nvarchar, description: "Stores JSON data as string (MSSQL doesn't have native JSON type)." }
                    ]
                },
                "boolean": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.bit, description: "Stores true or false values as 0 or 1." }
                    ]
                },
                "date": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.date, description: "Stores calendar dates (YYYY-MM-DD)." }
                    ]
                },
                "datetime": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.datetime, description: "Stores date and time without timezone." },
                        { label: create_field_metadata_dto_1.MSSQLType.datetime2, description: "High-precision date and time type." }
                    ]
                },
                "time": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.time, description: "Stores time values (HH:MM:SS)." }
                    ]
                },
                "relation": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.int, description: "Used for foreign keys referencing other entities." }
                    ]
                },
                "mediaSingle": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.varchar, description: "Stores file paths or URLs for single media files." }
                    ]
                },
                "mediaMultiple": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.varchar, description: "Stores file paths or URLs for multiple media files." }
                    ]
                },
                "email": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.nvarchar, description: "Stores email addresses." }
                    ]
                },
                "password": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.nvarchar, description: "Stores hashed or plain-text passwords." }
                    ]
                },
                "selectionStatic": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.nvarchar, description: "Used for predefined selection options." }
                    ]
                },
                "selectionDynamic": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.nvarchar, description: "Used for dynamic selection options." }
                    ]
                },
                "computed": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.nvarchar, description: "Represents computed or derived fields." }
                    ]
                },
                "uuid": {
                    ormTypes: [
                        { label: create_field_metadata_dto_1.MSSQLType.uniqueidentifier, description: "Stores universally unique identifiers (UUIDs)." }
                    ]
                }
            }
        };
    }
    async fetchCurrentFieldsBasedOnType(type) {
        return this.fetchCurrentFields(type);
    }
    fetchCurrentFields(solidFieldType) {
        switch (solidFieldType) {
            case create_field_metadata_dto_1.SolidFieldType.int:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "defaultValue",
                    "min",
                    "max",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName",
                    "enableAuditTracking",
                    "isPrimaryKey"
                ];
            case create_field_metadata_dto_1.SolidFieldType.bigint:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "defaultValue",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName",
                    "enableAuditTracking",
                    "isPrimaryKey"
                ];
            case create_field_metadata_dto_1.SolidFieldType.decimal:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "defaultValue",
                    "min",
                    "max",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName",
                    "enableAuditTracking"
                ];
            case create_field_metadata_dto_1.SolidFieldType.shortText:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "regexPattern",
                    "regexPatternNotMatchingErrorMsg",
                    "defaultValue",
                    "min",
                    "max",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName",
                    "isUserKey",
                    "enableAuditTracking",
                    "isPrimaryKey"
                ];
            case create_field_metadata_dto_1.SolidFieldType.longtext:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "regexPattern",
                    "regexPatternNotMatchingErrorMsg",
                    "defaultValue",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName",
                    "enableAuditTracking"
                ];
            case create_field_metadata_dto_1.SolidFieldType.richText:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName"
                ];
            case create_field_metadata_dto_1.SolidFieldType.json:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName"
                ];
            case create_field_metadata_dto_1.SolidFieldType.boolean:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "defaultValue",
                    "required",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName",
                    "enableAuditTracking"
                ];
            case create_field_metadata_dto_1.SolidFieldType.date:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "defaultValue",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName",
                    "enableAuditTracking"
                ];
            case create_field_metadata_dto_1.SolidFieldType.datetime:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "defaultValue",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName",
                    "enableAuditTracking"
                ];
            case create_field_metadata_dto_1.SolidFieldType.time:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "defaultValue",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName",
                    "enableAuditTracking"
                ];
            case create_field_metadata_dto_1.SolidFieldType.relation:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "relationType",
                    "relationCoModelFieldName",
                    "relationCreateInverse",
                    "relationCoModelSingularName",
                    "relationCoModelColumnName",
                    "relationModelModuleName",
                    "relationCascade",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName",
                    "relationJoinTableName",
                    "isRelationManyToManyOwner",
                    "relationFieldFixedFilter",
                    "enableAuditTracking"
                ];
            case create_field_metadata_dto_1.SolidFieldType.mediaSingle:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "mediaTypes",
                    "mediaMaxSizeKb",
                    "mediaStorageProviderId",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName"
                ];
            case create_field_metadata_dto_1.SolidFieldType.mediaMultiple:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "mediaTypes",
                    "mediaMaxSizeKb",
                    "mediaStorageProviderId",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName"
                ];
            case create_field_metadata_dto_1.SolidFieldType.email:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "regexPattern",
                    "regexPatternNotMatchingErrorMsg",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName",
                    "enableAuditTracking",
                    "isPrimaryKey"
                ];
            case create_field_metadata_dto_1.SolidFieldType.password:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "min",
                    "max",
                    "regexPattern",
                    "regexPatternNotMatchingErrorMsg",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName"
                ];
            case create_field_metadata_dto_1.SolidFieldType.selectionStatic:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "defaultValue",
                    "selectionStaticValues",
                    "selectionValueType",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName",
                    "enableAuditTracking",
                    "isMultiSelect"
                ];
            case create_field_metadata_dto_1.SolidFieldType.selectionDynamic:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "selectionDynamicProvider",
                    "selectionDynamicProviderCtxt",
                    "selectionValueType",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName",
                    "isUserKey",
                    "enableAuditTracking",
                    "isMultiSelect"
                ];
            case create_field_metadata_dto_1.SolidFieldType.computed:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "computedFieldValueType",
                    "computedFieldTriggerConfig",
                    "computedFieldValueProvider",
                    "computedFieldValueProviderCtxt",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName",
                    "isUserKey",
                    "enableAuditTracking"
                ];
            case create_field_metadata_dto_1.SolidFieldType.uuid:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "uuid",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName"
                ];
            default:
                return [
                    "name",
                    "displayName",
                    "description",
                    "type",
                    "ormType",
                    "isSystem",
                    "required",
                    "unique",
                    "index",
                    "private",
                    "encrypt",
                    "encryptionType",
                    "decryptWhen",
                    "columnName"
                ];
        }
    }
    async fetchAllDataSources() {
    }
    async upsert(updateDto) {
        const existingFieldMetadata = await this.fieldMetadataRepo.findOne({
            where: {
                model: { id: updateDto.model.id },
                name: updateDto.name
            }
        });
        if (existingFieldMetadata) {
            const updatedFieldMetadata = { ...existingFieldMetadata, ...updateDto };
            return this.fieldMetadataRepo.save(updatedFieldMetadata);
        }
        else {
            const fieldMetadata = this.fieldMetadataRepo.create(updateDto);
            return this.fieldMetadataRepo.save(fieldMetadata);
        }
    }
    async getSelectionDynamicValues(query) {
        const entity = await this.fieldMetadataRepo.findOne({
            where: {
                id: query.fieldId,
            },
        });
        if (!entity) {
            throw new common_1.NotFoundException(error_messages_1.ERROR_MESSAGES.FIELD_NOT_FOUND(query.fieldId));
        }
        const selectionDynamicProvider = entity.selectionDynamicProvider;
        const selectionDynamicProviderCtxt = JSON.parse(entity.selectionDynamicProviderCtxt ? entity.selectionDynamicProviderCtxt : '{}');
        selectionDynamicProviderCtxt['limit'] = query.limit;
        selectionDynamicProviderCtxt['offset'] = query.offset;
        const formValues = query.formValues || {};
        const parsedFormValues = typeof formValues === 'string' ? qs_1.default.parse(formValues, { allowDots: true }) : formValues;
        selectionDynamicProviderCtxt['formValues'] = parsedFormValues;
        const selectionProviderInstance = this.solidRegistry.getSelectionProviderInstance(selectionDynamicProvider);
        if (!selectionProviderInstance) {
            throw new common_1.NotFoundException(error_messages_1.ERROR_MESSAGES.PROVIDER_NOT_FOUND(selectionDynamicProvider));
        }
        return selectionProviderInstance.values(query.query, selectionDynamicProviderCtxt);
    }
    async getSelectionDynamicValue(query) {
        const entity = await this.fieldMetadataRepo.findOne({
            where: {
                id: query.fieldId,
            },
        });
        if (!entity) {
            throw new common_1.NotFoundException(error_messages_1.ERROR_MESSAGES.FIELD_NOT_FOUND(query.fieldId));
        }
        const selectionDynamicProvider = entity.selectionDynamicProvider;
        const selectionDynamicProviderCtxt = JSON.parse(entity.selectionDynamicProviderCtxt ? entity.selectionDynamicProviderCtxt : '{}');
        selectionDynamicProviderCtxt['limit'] = query.limit;
        selectionDynamicProviderCtxt['offset'] = query.offset;
        const formValues = query.formValues || {};
        const parsedFormValues = typeof formValues === 'string' ? qs_1.default.parse(formValues, { allowDots: true }) : formValues;
        selectionDynamicProviderCtxt['formValues'] = parsedFormValues;
        const selectionProviderInstance = this.solidRegistry.getSelectionProviderInstance(selectionDynamicProvider);
        if (!selectionProviderInstance) {
            throw new common_1.NotFoundException(error_messages_1.ERROR_MESSAGES.PROVIDER_NOT_FOUND(selectionDynamicProvider));
        }
        return selectionProviderInstance.value(query.optionValue, selectionDynamicProviderCtxt);
    }
    async updateRelationInverseFieldInFile(savedInverseField, inverseModelName, moduleName) {
        try {
            const filePath = await this.moduleMetadataHelperService.getModuleMetadataFilePath(moduleName);
            const metaData = await this.moduleMetadataHelperService.getModuleMetadataConfiguration(filePath);
            const fieldObject = await this.createFieldConfig(savedInverseField);
            const model = metaData.moduleMetadata.models.find((model) => model.singularName === inverseModelName);
            const fieldIndex = model.fields.findIndex((field) => field.name === savedInverseField.name);
            if (fieldIndex === -1) {
                model.fields.push(fieldObject);
            }
            else {
                model.fields[fieldIndex] = fieldObject;
            }
            const updatedContent = JSON.stringify(metaData, null, 2);
            await fs.writeFile(filePath, updatedContent);
        }
        catch (error) {
            this.logger.error('File creation failed:', error);
            throw new Error(error_messages_1.ERROR_MESSAGES.FILE_WRITE_FAILED);
        }
    }
    async createFieldConfig(field) {
        const fieldsRequiredBasedOnType = await this.fetchCurrentFieldsBasedOnType(field.type);
        const fieldObject = {};
        fieldsRequiredBasedOnType.forEach((requiredField) => {
            fieldObject[requiredField] = field[requiredField];
        });
        if (field.type == "mediaSingle" || field.type == "mediaMultiple") {
            if (field.mediaStorageProvider) {
                delete fieldObject.mediaStorageProviderId;
                fieldObject.mediaStorageProviderUserKey = field.mediaStorageProvider.name;
            }
        }
        if (field.isMarkedForRemoval) {
            fieldObject.isMarkedForRemoval = field.isMarkedForRemoval;
        }
        return fieldObject;
    }
    async resolveS3Url(resolveS3UrlDto) {
        const normalizedKey = this.normalizeS3Key(resolveS3UrlDto.s3Key);
        let resolvedBucketName = resolveS3UrlDto.bucketName;
        if (resolveS3UrlDto.mediaStorageProviderUserKey) {
            const mediaStorageProvider = await this.mediaStorageProviderMetadataRepository.findOne({
                where: {
                    name: resolveS3UrlDto.mediaStorageProviderUserKey
                }
            });
            if (!mediaStorageProvider) {
                throw new common_1.NotFoundException(`MediaStorageProviderMetadata with user key ${resolveS3UrlDto.mediaStorageProviderUserKey} not found`);
            }
            resolvedBucketName = mediaStorageProvider.bucketName;
        }
        this.logger.debug(`INSIDE::resolveS3Url:: resolvedBucketName: ${resolvedBucketName}`);
        const expiryInSeconds = resolveS3UrlDto.isPrivate == "true" ? 60 * 60 : 0;
        const url = await this.fileService.getUrl(`${resolvedBucketName}:${normalizedKey}`, {
            expiresIn: expiryInSeconds,
        });
        return { url: url };
    }
    normalizeS3Key(input) {
        try {
            const url = new URL(input);
            return decodeURIComponent(url.pathname.replace(/^\/+/, ""));
        }
        catch {
            return input;
        }
    }
};
exports.FieldMetadataService = FieldMetadataService;
exports.FieldMetadataService = FieldMetadataService = FieldMetadataService_1 = __decorate([
    (0, common_1.Injectable)(),
    __param(3, (0, typeorm_1.InjectDataSource)()),
    __metadata("design:paramtypes", [field_metadata_repository_1.FieldMetadataRepository,
        file_1.S3FileService,
        media_storage_provider_metadata_repository_1.MediaStorageProviderMetadataRepository,
        typeorm_2.DataSource,
        solid_registry_1.SolidRegistry,
        crud_helper_service_1.CrudHelperService,
        module_metadata_helper_service_1.ModuleMetadataHelperService])
], FieldMetadataService);
//# sourceMappingURL=field-metadata.service.js.map