"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 ModuleMetadataSeederService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ModuleMetadataSeederService = void 0;
const common_1 = require("@nestjs/common");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const dashboard_repository_1 = require("../repository/dashboard.repository");
const security_rule_repository_1 = require("../repository/security-rule.repository");
const authentication_service_1 = require("../services/authentication.service");
const email_template_service_1 = require("../services/email-template.service");
const list_of_values_service_1 = require("../services/list-of-values.service");
const setting_service_1 = require("../services/setting.service");
const sms_template_service_1 = require("../services/sms-template.service");
const user_service_1 = require("../services/user.service");
const typeorm_1 = require("typeorm");
const module_helper_1 = require("../helpers/module.helper");
const solid_registry_1 = require("../helpers/solid-registry");
const action_metadata_service_1 = require("../services/action-metadata.service");
const field_metadata_service_1 = require("../services/field-metadata.service");
const media_storage_provider_metadata_service_1 = require("../services/media-storage-provider-metadata.service");
const model_metadata_service_1 = require("../services/model-metadata.service");
const module_metadata_service_1 = require("../services/module-metadata.service");
const role_metadata_service_1 = require("../services/role-metadata.service");
const view_metadata_service_1 = require("../services/view-metadata.service");
const solid_core_metadata_json_1 = __importDefault(require("./seed-data/solid-core-metadata.json"));
const system_fields_seeder_service_1 = require("./system-fields-seeder.service");
const action_metadata_entity_1 = require("../entities/action-metadata.entity");
const menu_item_metadata_entity_1 = require("../entities/menu-item-metadata.entity");
const module_metadata_entity_1 = require("../entities/module-metadata.entity");
const role_metadata_entity_1 = require("../entities/role-metadata.entity");
const create_menu_item_metadata_dto_1 = require("../dtos/create-menu-item-metadata.dto");
const create_user_dto_1 = require("../dtos/create-user.dto");
const create_role_metadata_dto_1 = require("../dtos/create-role-metadata.dto");
const permission_metadata_repository_1 = require("../repository/permission-metadata.repository");
const saved_filters_repository_1 = require("../repository/saved-filters.repository");
const scheduled_job_repository_1 = require("../repository/scheduled-job.repository");
const setting_repository_1 = require("../repository/setting.repository");
const model_sequence_repository_1 = require("../repository/model-sequence.repository");
const model_sequence_entity_1 = require("../entities/model-sequence.entity");
const saved_filters_entity_1 = require("../entities/saved-filters.entity");
const scheduled_job_entity_1 = require("../entities/scheduled-job.entity");
const security_rule_entity_1 = require("../entities/security-rule.entity");
const list_of_values_entity_1 = require("../entities/list-of-values.entity");
const dashboard_entity_1 = require("../entities/dashboard.entity");
const field_metadata_entity_1 = require("../entities/field-metadata.entity");
const model_metadata_entity_1 = require("../entities/model-metadata.entity");
const permission_metadata_entity_1 = require("../entities/permission-metadata.entity");
const view_metadata_entity_1 = require("../entities/view-metadata.entity");
let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMetadataSeederService {
    constructor(moduleMetadataService, modelMetadataService, fieldMetadataService, mediaStorageProviderMetadataService, roleService, userService, authenticationService, solidActionService, solidViewService, emailTemplateService, smsTemplateService, listOfValuesService, permissionRepo, solidRegistry, settingService, settingsRepo, securityRuleRepo, systemFieldsSeederService, dashboardRepo, scheduledJobRepository, savedFiltersRepo, dataSource, modelSequenceRepo) {
        this.moduleMetadataService = moduleMetadataService;
        this.modelMetadataService = modelMetadataService;
        this.fieldMetadataService = fieldMetadataService;
        this.mediaStorageProviderMetadataService = mediaStorageProviderMetadataService;
        this.roleService = roleService;
        this.userService = userService;
        this.authenticationService = authenticationService;
        this.solidActionService = solidActionService;
        this.solidViewService = solidViewService;
        this.emailTemplateService = emailTemplateService;
        this.smsTemplateService = smsTemplateService;
        this.listOfValuesService = listOfValuesService;
        this.permissionRepo = permissionRepo;
        this.solidRegistry = solidRegistry;
        this.settingService = settingService;
        this.settingsRepo = settingsRepo;
        this.securityRuleRepo = securityRuleRepo;
        this.systemFieldsSeederService = systemFieldsSeederService;
        this.dashboardRepo = dashboardRepo;
        this.scheduledJobRepository = scheduledJobRepository;
        this.savedFiltersRepo = savedFiltersRepo;
        this.dataSource = dataSource;
        this.modelSequenceRepo = modelSequenceRepo;
        this.logger = new common_1.Logger(ModuleMetadataSeederService_1.name);
        this.enablePruning = false;
    }
    async seed(conf) {
        let currentModule = 'global';
        let currentStep = 'bootstrap';
        let modulesToSeed = null;
        try {
            this.enablePruning = Boolean(conf?.pruneMetadata);
            console.log(this.enablePruning ? '▶ Pruning enabled: metadata not present in JSON will be removed.' : '▶ Pruning disabled: existing metadata will be kept.');
            currentStep = 'seedGlobalMetadata';
            await this.seedGlobalMetadata();
            const seedDataFiles = this.seedDataFiles;
            this.logger.debug(`Found seed data for modules: ${seedDataFiles.map(s => s.moduleMetadata?.name)}`);
            currentStep = 'resolveModulesToSeed';
            if (conf && Array.isArray(conf.modulesToSeed)) {
                modulesToSeed = conf.modulesToSeed;
                console.log(`▶ Selective seeding enabled. Modules to seed: ${modulesToSeed.join(', ')}`);
                this.logger.log(`Selective seeding enabled. Modules to seed: ${modulesToSeed.join(', ')}`);
            }
            else {
                console.log(`▶ No modulesToSeed provided. Seeding ALL modules.`);
                this.logger.log(`No modulesToSeed provided. Seeding ALL modules.`);
            }
            const filteredSeedDataFiles = modulesToSeed ? seedDataFiles.filter((file) => modulesToSeed.includes(file.moduleMetadata?.name)) : seedDataFiles;
            if (filteredSeedDataFiles.length === 0) {
                this.logger.warn(`No modules matched the provided modulesToSeed list.`);
                return;
            }
            for (let i = 0; i < filteredSeedDataFiles.length; i++) {
                const overallMetadata = filteredSeedDataFiles[i];
                const moduleMetadata = overallMetadata.moduleMetadata;
                currentModule = moduleMetadata?.name ?? 'unknown';
                console.log(`▶ Seeding Metadata for Module: ${moduleMetadata.name}`);
                this.logger.log(`Seeding Metadata for Module: ${moduleMetadata.name}`);
                currentStep = 'seedMediaStorageProviders';
                this.logger.log(`Seeding Media Storage Providers`);
                const mediaStorageCounts = await this.seedMediaStorageProviders(overallMetadata.mediaStorageProviders);
                console.log(`${this.formatSeedResult(moduleMetadata.name, 'Media Storage Providers', mediaStorageCounts)}`);
                currentStep = 'seedModuleModelFields';
                this.logger.log(`Seeding Module / Model / Fields`);
                const moduleModelFieldCounts = await this.seedModuleModelFields(moduleMetadata);
                console.log(`${this.formatSeedResult(moduleMetadata.name, 'Module/Model/Fields', moduleModelFieldCounts)}`);
                currentStep = 'seedPermissions';
                this.logger.log(`Seeding Permissions`);
                const permissionCounts = await this.seedPermissions(overallMetadata);
                console.log(`${this.formatSeedResult(moduleMetadata.name, 'Permissions', permissionCounts)}`);
                currentStep = 'seedRoles';
                this.logger.log(`Seeding Roles`);
                const roleCounts = await this.seedRoles(overallMetadata);
                console.log(`${this.formatSeedResult(moduleMetadata.name, 'Roles', roleCounts)}`);
                currentStep = 'seedUsers';
                this.logger.log(`Seeding Users`);
                const userCounts = await this.seedUsers(overallMetadata);
                console.log(`${this.formatSeedResult(moduleMetadata.name, 'Users', userCounts)}`);
                currentStep = 'seedViews';
                this.logger.log(`Seeding Views`);
                const viewCounts = await this.seedViews(overallMetadata);
                console.log(`${this.formatSeedResult(moduleMetadata.name, 'Views', viewCounts)}`);
                currentStep = 'seedActions';
                this.logger.log(`Seeding Actions`);
                const actionCounts = await this.seedActions(overallMetadata);
                console.log(`${this.formatSeedResult(moduleMetadata.name, 'Actions', actionCounts)}`);
                currentStep = 'seedMenus';
                this.logger.log(`Seeding Menus`);
                const menuCounts = await this.seedMenus(overallMetadata);
                console.log(`${this.formatSeedResult(moduleMetadata.name, 'Menus', menuCounts)}`);
                currentStep = 'seedEmailTemplates';
                this.logger.log(`Seeding Email Templates`);
                const emailTemplateCounts = await this.seedEmailTemplates(overallMetadata, moduleMetadata.name);
                console.log(`${this.formatSeedResult(moduleMetadata.name, 'Email Templates', emailTemplateCounts)}`);
                currentStep = 'seedSmsTemplates';
                this.logger.log(`Seeding Sms Templates`);
                const smsTemplateCounts = await this.seedSmsTemplates(overallMetadata, moduleMetadata.name);
                console.log(`${this.formatSeedResult(moduleMetadata.name, 'Sms Templates', smsTemplateCounts)}`);
                currentStep = 'seedSecurityRules';
                this.logger.log(`Seeding Security Rules`);
                const securityRuleCounts = await this.seedSecurityRules(overallMetadata);
                console.log(`${this.formatSeedResult(moduleMetadata.name, 'Security Rules', securityRuleCounts)}`);
                currentStep = 'seedListOfValues';
                this.logger.log(`Seeding List Of Values`);
                const lovCounts = await this.seedListOfValues(moduleMetadata, overallMetadata);
                console.log(`${this.formatSeedResult(moduleMetadata.name, 'List Of Values', lovCounts)}`);
                currentStep = 'seedDashboards';
                this.logger.log(`Seeding Dashboards`);
                const dashboardCounts = await this.seedDashboards(moduleMetadata, overallMetadata);
                console.log(`${this.formatSeedResult(moduleMetadata.name, 'Dashboards', dashboardCounts)}`);
                currentStep = 'seedScheduledJobs';
                this.logger.log(`Seeding Scheduled Jobs`);
                const scheduledJobCounts = await this.seedScheduledJobs(moduleMetadata, overallMetadata);
                console.log(`${this.formatSeedResult(moduleMetadata.name, 'Scheduled Jobs', scheduledJobCounts)}`);
                currentStep = 'seedSavedFilters';
                this.logger.log(`Seeding Saved Filters`);
                const savedFilterCounts = await this.seedSavedFilters(moduleMetadata, overallMetadata);
                console.log(`${this.formatSeedResult(moduleMetadata.name, 'Saved Filters', savedFilterCounts)}`);
                currentStep = 'seedModelSequences';
                this.logger.log(`Seeding Model Sequences`);
                const modelSequenceCounts = await this.seedModelSequences(overallMetadata);
                console.log(`${this.formatSeedResult(moduleMetadata.name, 'Model Sequences', modelSequenceCounts)}`);
            }
            currentModule = 'global';
            currentStep = 'setupDefaultRolesWithPermissions';
            await this.setupDefaultRolesWithPermissions();
            console.log(`✔ Seeding completed.`);
        }
        catch (error) {
            this.logSeedFailureForCli(error, {
                moduleName: currentModule,
                step: currentStep,
                pruneEnabled: this.enablePruning,
                modulesToSeed,
            });
            throw error;
        }
    }
    async seedScheduledJobs(moduleMetadata, overallMetadata) {
        this.logger.debug(`[Start] Processing scheduled jobs for ${moduleMetadata.name}`);
        const scheduledJobs = overallMetadata.scheduledJobs;
        const pruned = this.enablePruning ? await this.pruneScheduledJobs(scheduledJobs, moduleMetadata.name) : 0;
        if (scheduledJobs?.length > 0) {
            await this.handleSeedScheduledJobs(scheduledJobs);
        }
        this.logger.debug(`[End] Processing scheduled jobs for ${moduleMetadata.name}`);
        return { pruned, upserted: scheduledJobs?.length ?? 0 };
    }
    async seedSavedFilters(moduleMetadata, overallMetadata) {
        this.logger.debug(`[Start] Processing saved filters for ${moduleMetadata.name}`);
        const savedFilters = overallMetadata.savedFilters;
        const pruned = this.enablePruning ? await this.pruneSavedFilters(savedFilters, moduleMetadata.name) : 0;
        if (savedFilters?.length > 0) {
            await this.handleSeedSavedFilters(savedFilters);
        }
        this.logger.debug(`[End] Processing saved filters for ${moduleMetadata.name}`);
        return { pruned, upserted: savedFilters?.length ?? 0 };
    }
    async seedDashboards(moduleMetadata, overallMetadata) {
        this.logger.debug(`[Start] Processing dashboards for ${moduleMetadata.name}`);
        const dashboards = overallMetadata.dashboards;
        const pruned = this.enablePruning ? await this.pruneDashboards(dashboards, moduleMetadata.name) : 0;
        await this.handleSeedDashboards(dashboards);
        this.logger.debug(`[End] Processing dashboards for ${moduleMetadata.name}`);
        return { pruned, upserted: dashboards?.length ?? 0 };
    }
    async seedListOfValues(moduleMetadata, overallMetadata) {
        this.logger.debug(`[Start] Processing List Of Values for ${moduleMetadata.name}`);
        const listOfValues = overallMetadata.listOfValues;
        const pruned = this.enablePruning ? await this.pruneListOfValues(listOfValues, moduleMetadata.name) : 0;
        await this.handleSeedListOfValues(listOfValues);
        this.logger.debug(`[End] Processing List Of Values for ${moduleMetadata.name}`);
        return { pruned, upserted: listOfValues?.length ?? 0 };
    }
    async setupDefaultRolesWithPermissions() {
        this.logger.debug(`About to add all permissions to the Admin role`);
        await this.roleService.addAllPermissionsToRole(create_role_metadata_dto_1.ADMIN_ROLE_NAME);
    }
    async seedSecurityRules(overallMetadata) {
        this.logger.debug(`[Start] Processing security rules`);
        const securityRules = overallMetadata.securityRules;
        const pruned = this.enablePruning ? await this.pruneSecurityRules(securityRules, overallMetadata?.moduleMetadata?.name) : 0;
        await this.handleSeedSecurityRules(securityRules);
        this.logger.debug(`[End] Processing security rules`);
        return { pruned, upserted: securityRules?.length ?? 0 };
    }
    async seedDefaultSettings() {
        this.logger.debug(`[Start] Processing settings`);
        await this.settingService.seedSystemAdminEditableAndAboveSettings();
        this.logger.debug(`[End] Processing settings`);
    }
    async seedSmsTemplates(overallMetadata, moduleName) {
        this.logger.debug(`[Start] Processing sms templates`);
        const smsTemplates = overallMetadata.smsTemplates;
        await this.handleSeedSmsTemplates(smsTemplates, moduleName);
        this.logger.debug(`[End] Processing sms templates`);
        return { pruned: 0, upserted: smsTemplates?.length ?? 0 };
    }
    async seedEmailTemplates(overallMetadata, moduleName) {
        this.logger.debug(`[Start] Processing email templates`);
        const emailTemplates = overallMetadata.emailTemplates;
        await this.handleSeedEmailTemplates(emailTemplates, moduleName);
        this.logger.debug(`[End] Processing email templates`);
        return { pruned: 0, upserted: emailTemplates?.length ?? 0 };
    }
    async seedMenus(overallMetadata) {
        this.logger.debug(`[Start] Processing menus`);
        const menus = overallMetadata.menus;
        const pruned = this.enablePruning ? await this.pruneMenus(menus, overallMetadata?.moduleMetadata?.name) : 0;
        await this.handleSeedMenus(menus);
        this.logger.debug(`[End] Processing menus`);
        return { pruned, upserted: menus?.length ?? 0 };
    }
    async seedActions(overallMetadata) {
        this.logger.debug(`[Start] Processing actions`);
        const actions = overallMetadata.actions;
        const pruned = this.enablePruning ? await this.pruneActions(actions, overallMetadata?.moduleMetadata?.name) : 0;
        await this.handleSeedActions(actions);
        this.logger.debug(`[End] Processing actions`);
        return { pruned, upserted: actions?.length ?? 0 };
    }
    async seedViews(overallMetadata) {
        this.logger.debug(`[Start] Processing views`);
        const views = overallMetadata.views;
        const pruned = this.enablePruning ? await this.pruneViews(views, overallMetadata?.moduleMetadata?.name) : 0;
        await this.handleSeedViews(views);
        this.logger.debug(`[End] Processing views`);
        return { pruned, upserted: views?.length ?? 0 };
    }
    async seedUsers(overallMetadata) {
        this.logger.debug(`[Start] Processing users`);
        const users = overallMetadata.users;
        await this.handleSeedUsers(users);
        this.logger.debug(`[End] Processing users`);
        return { pruned: 0, upserted: users?.length ?? 0 };
    }
    async seedRoles(overallMetadata) {
        this.logger.debug(`[Start] Processing roles`);
        await this.roleService.createRolesIfNotExists(overallMetadata.roles.map(role => { return { name: role.name }; }));
        for (const role of overallMetadata.roles) {
            if (role.permissions) {
                await this.roleService.addPermissionsToRole(role.name, role.permissions);
            }
        }
        this.logger.debug(`[End] Processing roles`);
        return { pruned: 0, upserted: overallMetadata.roles?.length ?? 0 };
    }
    async seedPermissions(overallMetadata) {
        this.logger.debug(`[Start] Processing permissions`);
        const permissions = overallMetadata.permissions ?? [];
        await this.handleSeedPermissions(permissions);
        this.logger.debug(`[End] Processing permissions`);
        return { pruned: 0, upserted: permissions?.length ?? 0 };
    }
    get seedDataFiles() {
        const typedSolidCoreMetadata = structuredClone(solid_core_metadata_json_1.default);
        const seedDataFiles = [typedSolidCoreMetadata];
        const enabledModules = (0, module_helper_1.getDynamicModuleNamesBasedOnMetadata)();
        for (const enabledModule of enabledModules) {
            const enabledModuleSeedFile = `module-metadata/${enabledModule}/${enabledModule}-metadata.json`;
            const fullPath = path.join(process.cwd(), enabledModuleSeedFile);
            if (fs.existsSync(fullPath)) {
                const overallMetadata = JSON.parse(fs.readFileSync(fullPath, 'utf-8'));
                seedDataFiles.push(overallMetadata);
            }
        }
        return seedDataFiles;
    }
    async seedGlobalMetadata() {
        this.logger.log(`Seeding Permissions`);
        await this.seedControllerPermissions();
        this.logger.log(`Seeding System Fields Metadata`);
        await this.seedDefaultSystemFields();
        this.logger.log(`Seeding Default Settings`);
        await this.seedDefaultSettings();
        this.logger.debug(`Global metadata seeding completed`);
    }
    async seedDefaultSystemFields() {
        await this.systemFieldsSeederService.seed();
    }
    async seedControllerPermissions() {
        const controllers = this.solidRegistry.getControllers();
        const permissionNames = [];
        for (let id = 0; id < controllers.length; id++) {
            try {
                const controller = controllers[id];
                const methods = controller.methods;
                for (let mId = 0; mId < methods.length; mId++) {
                    const methodName = methods[mId];
                    const permissionName = `${controller.name}.${methodName}`;
                    permissionNames.push(permissionName);
                    await this.createPermissionIfNotExists(permissionName);
                }
            }
            catch (error) {
                this.logger.error(error);
            }
        }
        if (this.enablePruning) {
            await this.prunePermissions(permissionNames);
        }
    }
    async createPermissionIfNotExists(permissionName) {
        const existingPermission = await this.permissionRepo.findOne({
            where: {
                name: permissionName
            }
        });
        if (!existingPermission) {
            this.logger.log(`Permission ${permissionName} does not exist, creating new.`);
            const newPermission = this.permissionRepo.create({
                name: permissionName
            });
            await this.permissionRepo.save(newPermission);
        }
    }
    async handleSeedPermissions(permissions) {
        for (const permission of permissions) {
            const permissionName = typeof permission === 'string' ? permission : permission?.name;
            if (permissionName) {
                await this.createPermissionIfNotExists(permissionName);
            }
        }
    }
    async seedMediaStorageProviders(mediaStorageProviders) {
        this.logger.debug(`[Start] Processing Media Storage Provider`);
        for (let i = 0; i < mediaStorageProviders.length; i++) {
            const mediaStorageProvider = mediaStorageProviders[i];
            await this.mediaStorageProviderMetadataService.upsert(mediaStorageProvider);
        }
        this.logger.debug(`[End] Processing Media Storage Provider`);
        return { pruned: 0, upserted: mediaStorageProviders?.length ?? 0 };
    }
    async seedModelSequences(overallMetadata) {
        this.logger.debug(`[Start] Processing model sequences`);
        const modelSequences = overallMetadata.modelSequences;
        const pruned = this.enablePruning ? await this.pruneModelSequences(modelSequences, overallMetadata?.moduleMetadata?.name) : 0;
        await this.handleSeedModelSequences(modelSequences);
        this.logger.debug(`[End] Processing model sequences`);
        return { pruned, upserted: modelSequences?.length ?? 0 };
    }
    async handleSeedEmailTemplates(emailTemplates, moduleName) {
        if (!emailTemplates) {
            return;
        }
        for (let i = 0; i < emailTemplates.length; i++) {
            const emailTemplate = emailTemplates[i];
            if (moduleName === 'solid-core') {
                let moduleRoot = null;
                try {
                    moduleRoot = path.dirname(require.resolve('@solidxai/core/package.json'));
                }
                catch (err) {
                    this.logger.debug('Could not resolve @solidxai/core from node_modules, assuming local execution');
                }
                const filePathInternal = 'src/seeders/seed-data/email-templates/';
                let filePath;
                if (moduleRoot) {
                    filePath = path.join(moduleRoot, filePathInternal, emailTemplate.body);
                }
                else {
                    const localCoreRoot = process.cwd();
                    filePath = path.join(localCoreRoot, filePathInternal, emailTemplate.body);
                }
                if (fs.existsSync(filePath)) {
                    emailTemplate.body = fs.readFileSync(filePath, 'utf-8');
                }
            }
            else {
                const emailTemplateHandlebar = `module-metadata/${moduleName}/email-templates/${emailTemplate.body}`;
                const fullPath = path.join(process.cwd(), emailTemplateHandlebar);
                if (fs.existsSync(fullPath)) {
                    emailTemplate.body = fs.readFileSync(fullPath, 'utf-8').toString();
                }
            }
            await this.emailTemplateService.removeByName(emailTemplate.name);
            await this.emailTemplateService.create(emailTemplate);
        }
    }
    async handleSeedSmsTemplates(smsTemplates, moduleName) {
        if (!smsTemplates) {
            return;
        }
        for (let i = 0; i < smsTemplates.length; i++) {
            const smsTemplate = smsTemplates[i];
            if (moduleName === 'solid-core') {
                let moduleRoot = null;
                try {
                    moduleRoot = path.dirname(require.resolve('@solidxai/core/package.json'));
                }
                catch (err) {
                    this.logger.debug('Could not resolve @solidxai/core from node_modules, assuming local execution');
                }
                const filePathInternal = 'src/seeders/seed-data/sms-templates/';
                let filePath;
                if (moduleRoot) {
                    filePath = path.join(moduleRoot, filePathInternal, smsTemplate.body);
                }
                else {
                    const localCoreRoot = process.cwd();
                    filePath = path.join(localCoreRoot, filePathInternal, smsTemplate.body);
                }
                if (fs.existsSync(filePath)) {
                    smsTemplate.body = fs.readFileSync(filePath, 'utf-8');
                }
            }
            else {
                const emailTemplateHandlebar = `module-metadata/${moduleName}/sms-templates/${smsTemplate.body}`;
                const fullPath = path.join(process.cwd(), emailTemplateHandlebar);
                if (fs.existsSync(fullPath)) {
                    smsTemplate.body = fs.readFileSync(fullPath, 'utf-8').toString();
                }
            }
            await this.smsTemplateService.removeByName(smsTemplate.name);
            await this.smsTemplateService.create(smsTemplate);
        }
    }
    async handleSeedMenus(menus) {
        if (!menus) {
            return;
        }
        await this.dataSource.transaction(async (trx) => {
            const menuRepo = trx.getRepository(menu_item_metadata_entity_1.MenuItemMetadata);
            const roleRepo = trx.getRepository(role_metadata_entity_1.RoleMetadata);
            const actionRepo = trx.getRepository(action_metadata_entity_1.ActionMetadata);
            const moduleRepo = trx.getRepository(module_metadata_entity_1.ModuleMetadata);
            for (const m of menus) {
                const action = m.actionUserKey
                    ? await actionRepo.findOne({ where: { name: m.actionUserKey }, select: ["id"] })
                    : null;
                const module = m.moduleUserKey
                    ? await moduleRepo.findOne({ where: { name: m.moduleUserKey }, select: ["id"] })
                    : null;
                const parentMenuItem = m.parentMenuItemUserKey
                    ? await menuRepo.findOne({ where: { name: m.parentMenuItemUserKey }, select: ["id"] })
                    : null;
                const existing = await menuRepo.findOne({
                    where: { name: m.name },
                    select: ["id"],
                });
                const base = {
                    name: m.name,
                    displayName: m.displayName,
                    action,
                    module,
                    parentMenuItem,
                    sequenceNumber: m.sequenceNumber,
                    iconName: m.iconName,
                };
                const entity = menuRepo.create(existing ? { id: existing.id, ...base } : base);
                await menuRepo.save(entity);
            }
            const seeded = await menuRepo.find({
                where: { name: (0, typeorm_1.In)(menus.map((m) => m.name)) },
                select: ["id", "name"],
            });
            const idByName = new Map(seeded.map(s => [s.name, s.id]));
            const admin = await roleRepo.findOne({ where: { name: create_role_metadata_dto_1.ADMIN_ROLE_NAME }, select: ["id", "name"] });
            const allRoleNames = new Set();
            for (const m of menus)
                (m.roles ?? []).forEach((r) => allRoleNames.add(r));
            if (admin)
                allRoleNames.add(admin.name);
            const roles = await roleRepo.find({
                where: { name: (0, typeorm_1.In)([...allRoleNames]) },
                select: ["id", "name"],
            });
            const roleByName = new Map(roles.map(r => [r.name, r]));
            const joinRows = [];
            for (const m of menus) {
                const menuId = idByName.get(m.name);
                const roleNames = new Set([...(m.roles ?? []), admin?.name].filter(Boolean));
                for (const rn of roleNames) {
                    const role = roleByName.get(rn);
                    if (role)
                        joinRows.push({ menuId, roleId: role.id });
                }
            }
            const menuIds = [...new Set(joinRows.map(r => r.menuId))];
            if (menuIds.length) {
                await trx
                    .createQueryBuilder()
                    .delete()
                    .from(create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME)
                    .where(`${create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME_MENU_COL} IN (:...ids)`, { ids: menuIds })
                    .execute();
            }
            if (joinRows.length) {
                const values = joinRows.map(r => ({
                    [create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME_MENU_COL]: r.menuId,
                    [create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME_ROLE_COL]: r.roleId,
                }));
                await trx
                    .createQueryBuilder()
                    .insert()
                    .into(create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME)
                    .values(values)
                    .execute();
            }
        });
    }
    async handleSeedActions(actions) {
        if (!actions) {
            return;
        }
        for (let j = 0; j < actions.length; j++) {
            const actionData = actions[j];
            actionData['module'] = await this.moduleMetadataService.findOneByUserKey(actionData.moduleUserKey);
            if (actionData.type === 'solid') {
                actionData['model'] = await this.modelMetadataService.findOneByUserKey(actionData.modelUserKey);
                actionData['view'] = await this.solidViewService.findOneByUserKey(actionData.viewUserKey);
            }
            else {
                if (actionData.modelUserKey) {
                    actionData['model'] = await this.modelMetadataService.findOneByUserKey(actionData.modelUserKey);
                }
            }
            await this.solidActionService.upsert(actionData);
        }
    }
    async handleSeedViews(views) {
        if (!views) {
            return;
        }
        for (let j = 0; j < views.length; j++) {
            const viewData = views[j];
            viewData['layout'] = JSON.stringify(viewData['layout'], null, 2);
            viewData['module'] = await this.moduleMetadataService.findOneByUserKey(viewData.moduleUserKey);
            viewData['model'] = await this.modelMetadataService.findOneByUserKey(viewData.modelUserKey);
            await this.solidViewService.upsert(viewData);
        }
    }
    async handleSeedUsers(users) {
        if (!users) {
            return;
        }
        for (let l = 0; l < users.length; l++) {
            const user = users[l];
            let exisitingUser = await this.userService.findOneByUsername(user.username);
            if (!exisitingUser) {
                if (user.username === 'sa') {
                    user.password = create_user_dto_1.DEFAULT_SA_PASSWORD;
                }
                exisitingUser = await this.authenticationService.signUp(user);
                this.logger.log(`Newly created user ${user.username}`);
            }
        }
    }
    async seedModuleModelFields(moduleMetadata) {
        this.logger.debug(`[Start] Processing module metadata`);
        const module = await this.moduleMetadataService.upsert(moduleMetadata);
        let pruned = 0;
        let upserted = 1;
        const modelsMetadata = moduleMetadata.models;
        upserted += modelsMetadata?.length ?? 0;
        for (let j = 0; j < modelsMetadata.length; j++) {
            const modelMetadata = modelsMetadata[j];
            modelMetadata['module'] = module;
            const { fields: fieldsMetadata, ...modelMetaDataWithoutFields } = modelMetadata;
            if (modelMetadata.isChild && modelMetadata.parentModelUserKey) {
                const parentModel = await this.modelMetadataService.findOneByUserKey(modelMetadata.parentModelUserKey);
                modelMetaDataWithoutFields['parentModel'] = parentModel;
            }
            await this.modelMetadataService.upsert(modelMetaDataWithoutFields);
            const model = await this.modelMetadataService.findOneBySingularName(modelMetadata.singularName);
            if (this.enablePruning) {
                pruned += await this.pruneFieldsForModel(model, fieldsMetadata);
            }
            let userKeyField = null;
            const userKeyFieldName = modelMetadata.userKeyFieldUserKey;
            upserted += fieldsMetadata?.length ?? 0;
            for (let k = 0; k < fieldsMetadata.length; k++) {
                const fieldMetadata = fieldsMetadata[k];
                fieldMetadata['model'] = model;
                if (fieldMetadata.mediaStorageProviderUserKey) {
                    fieldMetadata['mediaStorageProvider'] = await this.mediaStorageProviderMetadataService.findOneByUserKey(fieldMetadata.mediaStorageProviderUserKey);
                }
                const affectedField = await this.fieldMetadataService.upsert(fieldMetadata);
                if (fieldMetadata.name === userKeyFieldName || fieldMetadata.isUserKey) {
                    const { model, ...fieldData } = affectedField;
                    userKeyField = fieldData;
                }
            }
            if (userKeyField) {
                modelMetaDataWithoutFields['userKeyField'] = userKeyField;
                await this.modelMetadataService.upsert(modelMetaDataWithoutFields);
            }
        }
        if (this.enablePruning) {
            pruned += await this.pruneModels(modelsMetadata, moduleMetadata.name);
        }
        this.logger.debug(`[End] Processing module metadata`);
        return { pruned, upserted };
    }
    async handleSeedSecurityRules(rulesDto) {
        if (!rulesDto || rulesDto.length === 0) {
            this.logger.debug(`No security rules found to seed`);
            return;
        }
        for (const dto of rulesDto) {
            await this.securityRuleRepo.upsertWithDto({ ...dto, securityRuleConfig: JSON.stringify(dto.securityRuleConfig) });
        }
    }
    async handleSeedListOfValues(listOfValuesDto) {
        if (!listOfValuesDto || listOfValuesDto.length === 0) {
            this.logger.debug(`No List Of Values found to seed`);
            return;
        }
        for (let j = 0; j < listOfValuesDto.length; j++) {
            const listOfValueDto = listOfValuesDto[j];
            listOfValueDto['module'] = await this.moduleMetadataService.findOneByUserKey(listOfValueDto.moduleUserKey);
            await this.listOfValuesService.upsert(listOfValuesDto[j]);
        }
    }
    async handleSeedDashboards(dashboardDtos) {
        if (!dashboardDtos || dashboardDtos.length === 0) {
            this.logger.debug(`No dashboards found to seed`);
            return;
        }
        for (const dto of dashboardDtos) {
            await this.dashboardRepo.upsertWithDto(dto);
        }
    }
    async handleSeedScheduledJobs(createScheduledJobDto) {
        if (!createScheduledJobDto || createScheduledJobDto.length === 0) {
            this.logger.debug(`No scheduled jobs found to seed`);
            return;
        }
        for (const dto of createScheduledJobDto) {
            await this.scheduledJobRepository.upsertWithDto(dto);
        }
    }
    async handleSeedSavedFilters(createSavedFilterDto) {
        if (!createSavedFilterDto || createSavedFilterDto.length === 0) {
            this.logger.debug(`No saved filters found to seed`);
            return;
        }
        for (const dto of createSavedFilterDto) {
            this.validateSavedFilterQueryJsonWrapper(dto);
            await this.savedFiltersRepo.upsertWithDto({ ...dto, filterQueryJson: JSON.stringify(dto.filterQueryJson), isSeeded: true });
        }
    }
    validateSavedFilterQueryJsonWrapper(dto) {
        const filterName = dto?.name ?? '<unnamed>';
        const filterQueryJson = dto?.filterQueryJson;
        const baseErrorMessage = `Invalid saved filter "${filterName}": filterQueryJson must be wrapped with a top-level "$or" or "$and". ` +
            `Example: {"$or":[{"employeeStatus":{"$eq":"Active"}}]}`;
        if (!filterQueryJson || typeof filterQueryJson !== 'object' || Array.isArray(filterQueryJson)) {
            throw new Error(baseErrorMessage);
        }
        const topLevelKeys = Object.keys(filterQueryJson);
        const hasLogicalWrapper = topLevelKeys.includes('$or') || topLevelKeys.includes('$and');
        if (!hasLogicalWrapper) {
            const receivedKeys = topLevelKeys.length > 0 ? topLevelKeys.join(', ') : '(none)';
            throw new Error(`${baseErrorMessage}. Received top-level keys: ${receivedKeys}`);
        }
    }
    async handleSeedModelSequences(modelSequencesDto) {
        if (!modelSequencesDto || modelSequencesDto.length === 0) {
            this.logger.debug(`No Model Sequences found to seed`);
            return;
        }
        for (const dto of modelSequencesDto) {
            await this.modelSequenceRepo.upsertWithDto(dto);
        }
    }
    async pruneModelSequences(modelSequencesDto, moduleName) {
        if (!moduleName) {
            this.logger.warn(`Skipping model sequence prune: missing module name in metadata.`);
            return 0;
        }
        const sequences = modelSequencesDto ?? [];
        const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
        if (!module) {
            this.logger.warn(`Skipping model sequence prune: module not found for ${moduleName}.`);
            return 0;
        }
        const sequenceNames = [...new Set(sequences.map(dto => dto.sequenceName).filter(Boolean))];
        const repo = this.dataSource.getRepository(model_sequence_entity_1.ModelSequence);
        const idsToDeleteQuery = repo
            .createQueryBuilder('ms')
            .select('ms.id', 'id')
            .innerJoin('ms.module', 'module')
            .where('module.id = :moduleId', { moduleId: module.id });
        if (sequenceNames.length > 0) {
            idsToDeleteQuery.andWhere('ms.sequenceName NOT IN (:...sequenceNames)', { sequenceNames });
        }
        const rows = await idsToDeleteQuery.getRawMany();
        const ids = rows.map((row) => row.id);
        if (ids.length > 0) {
            const result = await repo
                .createQueryBuilder()
                .delete()
                .from(model_sequence_entity_1.ModelSequence)
                .whereInIds(ids)
                .execute();
            return result.affected ?? 0;
        }
        return 0;
    }
    async pruneSavedFilters(savedFiltersDto, moduleName) {
        if (!moduleName) {
            this.logger.warn(`Skipping saved filters prune: missing module name in metadata.`);
            return 0;
        }
        const savedFilters = savedFiltersDto ?? [];
        const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
        if (!module) {
            this.logger.warn(`Skipping saved filters prune: module not found for ${moduleName}.`);
            return 0;
        }
        const filterNames = [...new Set(savedFilters.map(dto => dto.name).filter(Boolean))];
        const repo = this.dataSource.getRepository(saved_filters_entity_1.SavedFilters);
        const idsToDeleteQuery = repo
            .createQueryBuilder('sf')
            .select('sf.id', 'id')
            .innerJoin('sf.view', 'view')
            .innerJoin('view.module', 'module')
            .where('module.id = :moduleId', { moduleId: module.id });
        if (filterNames.length > 0) {
            idsToDeleteQuery.andWhere('sf.name NOT IN (:...filterNames)', { filterNames });
        }
        const rows = await idsToDeleteQuery.getRawMany();
        const ids = rows.map((row) => row.id);
        if (ids.length > 0) {
            const result = await repo
                .createQueryBuilder()
                .delete()
                .from(saved_filters_entity_1.SavedFilters)
                .whereInIds(ids)
                .execute();
            return result.affected ?? 0;
        }
        return 0;
    }
    async pruneScheduledJobs(scheduledJobsDto, moduleName) {
        if (!moduleName) {
            this.logger.warn(`Skipping scheduled jobs prune: missing module name in metadata.`);
            return 0;
        }
        const scheduledJobs = scheduledJobsDto ?? [];
        const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
        if (!module) {
            this.logger.warn(`Skipping scheduled jobs prune: module not found for ${moduleName}.`);
            return 0;
        }
        const scheduleNames = [...new Set(scheduledJobs.map(dto => dto.scheduleName).filter(Boolean))];
        const repo = this.dataSource.getRepository(scheduled_job_entity_1.ScheduledJob);
        const idsToDeleteQuery = repo
            .createQueryBuilder('sj')
            .select('sj.id', 'id')
            .innerJoin('sj.module', 'module')
            .where('module.id = :moduleId', { moduleId: module.id });
        if (scheduleNames.length > 0) {
            idsToDeleteQuery.andWhere('sj.scheduleName NOT IN (:...scheduleNames)', { scheduleNames });
        }
        const rows = await idsToDeleteQuery.getRawMany();
        const ids = rows.map((row) => row.id);
        if (ids.length > 0) {
            const result = await repo
                .createQueryBuilder()
                .delete()
                .from(scheduled_job_entity_1.ScheduledJob)
                .whereInIds(ids)
                .execute();
            return result.affected ?? 0;
        }
        return 0;
    }
    async pruneSecurityRules(securityRulesDto, moduleName) {
        if (!moduleName) {
            this.logger.warn(`Skipping security rules prune: missing module name in metadata.`);
            return 0;
        }
        const securityRules = securityRulesDto ?? [];
        const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
        if (!module) {
            this.logger.warn(`Skipping security rules prune: module not found for ${moduleName}.`);
            return 0;
        }
        const ruleNames = [...new Set(securityRules.map(dto => dto.name).filter(Boolean))];
        const repo = this.dataSource.getRepository(security_rule_entity_1.SecurityRule);
        const idsToDeleteQuery = repo
            .createQueryBuilder('sr')
            .select('sr.id', 'id')
            .innerJoin('sr.modelMetadata', 'model')
            .innerJoin('model.module', 'module')
            .where('module.id = :moduleId', { moduleId: module.id });
        if (ruleNames.length > 0) {
            idsToDeleteQuery.andWhere('sr.name NOT IN (:...ruleNames)', { ruleNames });
        }
        const rows = await idsToDeleteQuery.getRawMany();
        const ids = rows.map((row) => row.id);
        if (ids.length > 0) {
            const result = await repo
                .createQueryBuilder()
                .delete()
                .from(security_rule_entity_1.SecurityRule)
                .whereInIds(ids)
                .execute();
            return result.affected ?? 0;
        }
        return 0;
    }
    async pruneListOfValues(listOfValuesDto, moduleName) {
        if (!moduleName) {
            this.logger.warn(`Skipping list of values prune: missing module name in metadata.`);
            return 0;
        }
        const listOfValues = listOfValuesDto ?? [];
        const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
        if (!module) {
            this.logger.warn(`Skipping list of values prune: module not found for ${moduleName}.`);
            return 0;
        }
        const pairs = listOfValues
            .filter(dto => dto.type && dto.value)
            .map(dto => ({ type: dto.type, value: dto.value }));
        const repo = this.dataSource.getRepository(list_of_values_entity_1.ListOfValues);
        const idsToDeleteQuery = repo
            .createQueryBuilder('lov')
            .select('lov.id', 'id')
            .innerJoin('lov.module', 'module')
            .where('module.id = :moduleId', { moduleId: module.id });
        if (pairs.length > 0) {
            const conditions = pairs.map((_, i) => `(lov.type = :t${i} AND lov.value = :v${i})`).join(' OR ');
            const params = pairs.reduce((acc, pair, i) => {
                acc[`t${i}`] = pair.type;
                acc[`v${i}`] = pair.value;
                return acc;
            }, {});
            idsToDeleteQuery.andWhere(`NOT (${conditions})`, params);
        }
        const rows = await idsToDeleteQuery.getRawMany();
        const ids = rows.map((row) => row.id);
        if (ids.length > 0) {
            const result = await repo
                .createQueryBuilder()
                .delete()
                .from(list_of_values_entity_1.ListOfValues)
                .whereInIds(ids)
                .execute();
            return result.affected ?? 0;
        }
        return 0;
    }
    async pruneDashboards(dashboardsDto, moduleName) {
        if (!moduleName) {
            this.logger.warn(`Skipping dashboards prune: missing module name in metadata.`);
            return 0;
        }
        const dashboards = dashboardsDto ?? [];
        const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
        if (!module) {
            this.logger.warn(`Skipping dashboards prune: module not found for ${moduleName}.`);
            return 0;
        }
        const dashboardNames = [...new Set(dashboards.map(dto => dto.name).filter(Boolean))];
        const repo = this.dataSource.getRepository(dashboard_entity_1.Dashboard);
        const idsToDeleteQuery = repo
            .createQueryBuilder('db')
            .select('db.id', 'id')
            .innerJoin('db.module', 'module')
            .where('module.id = :moduleId', { moduleId: module.id });
        if (dashboardNames.length > 0) {
            idsToDeleteQuery.andWhere('db.name NOT IN (:...dashboardNames)', { dashboardNames });
        }
        const rows = await idsToDeleteQuery.getRawMany();
        const ids = rows.map((row) => row.id);
        if (ids.length > 0) {
            const result = await repo
                .createQueryBuilder()
                .delete()
                .from(dashboard_entity_1.Dashboard)
                .whereInIds(ids)
                .execute();
            return result.affected ?? 0;
        }
        return 0;
    }
    async pruneMenus(menusDto, moduleName) {
        if (!moduleName) {
            this.logger.warn(`Skipping menus prune: missing module name in metadata.`);
            return 0;
        }
        const menus = menusDto ?? [];
        const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
        if (!module) {
            this.logger.warn(`Skipping menus prune: module not found for ${moduleName}.`);
            return 0;
        }
        const menuNames = [...new Set(menus.map(m => m.name).filter(Boolean))];
        const repo = this.dataSource.getRepository(menu_item_metadata_entity_1.MenuItemMetadata);
        const idsToDeleteQuery = repo
            .createQueryBuilder('menu')
            .select('menu.id', 'id')
            .innerJoin('menu.module', 'module')
            .where('module.id = :moduleId', { moduleId: module.id });
        if (menuNames.length > 0) {
            idsToDeleteQuery.andWhere('menu.name NOT IN (:...menuNames)', { menuNames });
        }
        const rows = await idsToDeleteQuery.getRawMany();
        const ids = rows.map((row) => row.id);
        if (ids.length > 0) {
            await this.dataSource
                .createQueryBuilder()
                .delete()
                .from(create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME)
                .where(`${create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME_MENU_COL} IN (:...ids)`, { ids })
                .execute();
        }
        if (ids.length > 0) {
            const result = await repo
                .createQueryBuilder()
                .delete()
                .from(menu_item_metadata_entity_1.MenuItemMetadata)
                .whereInIds(ids)
                .execute();
            return result.affected ?? 0;
        }
        return 0;
    }
    async pruneViews(viewsDto, moduleName) {
        if (!moduleName) {
            this.logger.warn(`Skipping views prune: missing module name in metadata.`);
            return 0;
        }
        const views = viewsDto ?? [];
        const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
        if (!module) {
            this.logger.warn(`Skipping views prune: module not found for ${moduleName}.`);
            return 0;
        }
        const viewNames = [...new Set(views.map((v) => v.name).filter(Boolean))];
        const repo = this.dataSource.getRepository(view_metadata_entity_1.ViewMetadata);
        const idsToDeleteQuery = repo
            .createQueryBuilder('view')
            .select('view.id', 'id')
            .innerJoin('view.module', 'module')
            .where('module.id = :moduleId', { moduleId: module.id });
        if (viewNames.length > 0) {
            idsToDeleteQuery.andWhere('view.name NOT IN (:...viewNames)', { viewNames });
        }
        const rows = await idsToDeleteQuery.getRawMany();
        const ids = rows.map((row) => row.id);
        if (ids.length > 0) {
            const actionRepo = this.dataSource.getRepository(action_metadata_entity_1.ActionMetadata);
            const actionRows = await actionRepo
                .createQueryBuilder('action')
                .select('action.id', 'id')
                .innerJoin('action.view', 'view')
                .where('view.id IN (:...viewIds)', { viewIds: ids })
                .getRawMany();
            const actionIds = actionRows.map((row) => row.id);
            if (actionIds.length > 0) {
                const result = await actionRepo
                    .createQueryBuilder()
                    .delete()
                    .from(action_metadata_entity_1.ActionMetadata)
                    .whereInIds(actionIds)
                    .execute();
                if ((result.affected ?? 0) === 0) {
                    this.logger.warn(`No actions deleted for pruned views in module ${moduleName}.`);
                }
            }
            const result = await repo
                .createQueryBuilder()
                .delete()
                .from(view_metadata_entity_1.ViewMetadata)
                .whereInIds(ids)
                .execute();
            return result.affected ?? 0;
        }
        return 0;
    }
    async pruneActions(actionsDto, moduleName) {
        if (!moduleName) {
            this.logger.warn(`Skipping actions prune: missing module name in metadata.`);
            return 0;
        }
        const actions = actionsDto ?? [];
        const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
        if (!module) {
            this.logger.warn(`Skipping actions prune: module not found for ${moduleName}.`);
            return 0;
        }
        const actionNames = [...new Set(actions.map((a) => a.name).filter(Boolean))];
        const repo = this.dataSource.getRepository(action_metadata_entity_1.ActionMetadata);
        const idsToDeleteQuery = repo
            .createQueryBuilder('action')
            .select('action.id', 'id')
            .innerJoin('action.module', 'module')
            .where('module.id = :moduleId', { moduleId: module.id });
        if (actionNames.length > 0) {
            idsToDeleteQuery.andWhere('action.name NOT IN (:...actionNames)', { actionNames });
        }
        const rows = await idsToDeleteQuery.getRawMany();
        const ids = rows.map((row) => row.id);
        if (ids.length > 0) {
            const menuRepo = this.dataSource.getRepository(menu_item_metadata_entity_1.MenuItemMetadata);
            const menuRows = await menuRepo
                .createQueryBuilder('menu')
                .select('menu.id', 'id')
                .innerJoin('menu.action', 'action')
                .where('action.id IN (:...actionIds)', { actionIds: ids })
                .getRawMany();
            const menuIds = menuRows.map((row) => row.id);
            if (menuIds.length > 0) {
                await this.dataSource
                    .createQueryBuilder()
                    .delete()
                    .from(create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME)
                    .where(`${create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME_MENU_COL} IN (:...ids)`, { ids: menuIds })
                    .execute();
                await menuRepo
                    .createQueryBuilder()
                    .delete()
                    .from(menu_item_metadata_entity_1.MenuItemMetadata)
                    .whereInIds(menuIds)
                    .execute();
            }
            const result = await repo
                .createQueryBuilder()
                .delete()
                .from(action_metadata_entity_1.ActionMetadata)
                .whereInIds(ids)
                .execute();
            return result.affected ?? 0;
        }
        return 0;
    }
    async pruneFieldsForModel(model, fieldsMetadata) {
        if (!model) {
            this.logger.warn(`Skipping fields prune: model not found.`);
            return 0;
        }
        const fields = fieldsMetadata ?? [];
        const fieldNames = [...new Set(fields.map(f => f.name).filter(Boolean))];
        const repo = this.dataSource.getRepository(field_metadata_entity_1.FieldMetadata);
        const idsToDeleteQuery = repo
            .createQueryBuilder('field')
            .select('field.id', 'id')
            .innerJoin('field.model', 'model')
            .where('model.id = :modelId', { modelId: model.id })
            .andWhere('field.isSystem = :isSystem', { isSystem: false });
        if (fieldNames.length > 0) {
            idsToDeleteQuery.andWhere('field.name NOT IN (:...fieldNames)', { fieldNames });
        }
        const rows = await idsToDeleteQuery.getRawMany();
        const ids = rows.map((row) => row.id);
        if (ids.length > 0) {
            const result = await repo
                .createQueryBuilder()
                .delete()
                .from(field_metadata_entity_1.FieldMetadata)
                .whereInIds(ids)
                .execute();
            return result.affected ?? 0;
        }
        return 0;
    }
    async pruneModels(modelsMetadata, moduleName) {
        if (!moduleName) {
            this.logger.warn(`Skipping models prune: missing module name in metadata.`);
            return 0;
        }
        const models = modelsMetadata ?? [];
        const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
        if (!module) {
            this.logger.warn(`Skipping models prune: module not found for ${moduleName}.`);
            return 0;
        }
        const modelNames = [...new Set(models.map(m => m.singularName).filter(Boolean))];
        const repo = this.dataSource.getRepository(model_metadata_entity_1.ModelMetadata);
        const idsToDeleteQuery = repo
            .createQueryBuilder('model')
            .select('model.id', 'id')
            .innerJoin('model.module', 'module')
            .where('module.id = :moduleId', { moduleId: module.id })
            .andWhere('model.isSystem = :isSystem', { isSystem: false });
        if (modelNames.length > 0) {
            idsToDeleteQuery.andWhere('model.singularName NOT IN (:...modelNames)', { modelNames });
        }
        const rows = await idsToDeleteQuery.getRawMany();
        const ids = rows.map((row) => row.id);
        if (ids.length > 0) {
            const result = await repo
                .createQueryBuilder()
                .delete()
                .from(model_metadata_entity_1.ModelMetadata)
                .whereInIds(ids)
                .execute();
            return result.affected ?? 0;
        }
        return 0;
    }
    getRolePermissionJoinInfo() {
        const roleMetadata = this.dataSource.getMetadata(role_metadata_entity_1.RoleMetadata);
        const relation = roleMetadata.relations.find((r) => r.propertyName === 'permissions');
        if (!relation || !relation.junctionEntityMetadata) {
            this.logger.warn(`Role-permission join table metadata not found; skipping join cleanup.`);
            return null;
        }
        const permissionIdColumn = relation.inverseJoinColumns[0]?.databaseName;
        if (!permissionIdColumn) {
            this.logger.warn(`Role-permission join column not found; skipping join cleanup.`);
            return null;
        }
        return {
            tableName: relation.junctionEntityMetadata.tableName,
            permissionIdColumn,
        };
    }
    async prunePermissions(permissionNames) {
        const uniqueNames = [...new Set(permissionNames.filter(Boolean))];
        const repo = this.dataSource.getRepository(permission_metadata_entity_1.PermissionMetadata);
        const idsToDeleteQuery = repo
            .createQueryBuilder('perm')
            .select('perm.id', 'id');
        if (uniqueNames.length > 0) {
            idsToDeleteQuery.andWhere('perm.name NOT IN (:...names)', { names: uniqueNames });
        }
        const rows = await idsToDeleteQuery.getRawMany();
        const ids = rows.map((row) => row.id);
        const joinInfo = this.getRolePermissionJoinInfo();
        if (joinInfo && ids.length > 0) {
            await this.dataSource
                .createQueryBuilder()
                .delete()
                .from(joinInfo.tableName)
                .where(`${joinInfo.permissionIdColumn} IN (:...ids)`, { ids })
                .execute();
        }
        if (ids.length > 0) {
            const result = await repo
                .createQueryBuilder()
                .delete()
                .from(permission_metadata_entity_1.PermissionMetadata)
                .whereInIds(ids)
                .execute();
            return result.affected ?? 0;
        }
        return 0;
    }
    logSeedFailureForCli(error, context) {
        const err = error instanceof Error ? error : new Error(String(error));
        const stackLines = (err.stack ?? '')
            .split('\n')
            .slice(0, 8)
            .map((line) => line.trim())
            .filter(Boolean);
        const logPayload = {
            module: context.moduleName,
            step: context.step,
            pruneEnabled: context.pruneEnabled,
            modulesToSeed: context.modulesToSeed?.length ? context.modulesToSeed : 'ALL',
            error: {
                name: err.name,
                message: err.message,
                stackPreview: stackLines.length > 0 ? stackLines : undefined,
            },
        };
        console.log('✖ Seeding failed');
        console.log(JSON.stringify(logPayload, null, 2));
    }
    formatSeedResult(moduleName, label, counts) {
        if (this.enablePruning) {
            return `✔ [${moduleName}] ${label} seeded (pruned ${counts.pruned}, upserted ${counts.upserted})`;
        }
        return `✔ [${moduleName}] ${label} seeded (upserted ${counts.upserted})`;
    }
};
exports.ModuleMetadataSeederService = ModuleMetadataSeederService;
exports.ModuleMetadataSeederService = ModuleMetadataSeederService = ModuleMetadataSeederService_1 = __decorate([
    (0, common_1.Injectable)(),
    __param(1, (0, common_1.Inject)((0, common_1.forwardRef)(() => model_metadata_service_1.ModelMetadataService))),
    __metadata("design:paramtypes", [module_metadata_service_1.ModuleMetadataService,
        model_metadata_service_1.ModelMetadataService,
        field_metadata_service_1.FieldMetadataService,
        media_storage_provider_metadata_service_1.MediaStorageProviderMetadataService,
        role_metadata_service_1.RoleMetadataService,
        user_service_1.UserService,
        authentication_service_1.AuthenticationService,
        action_metadata_service_1.ActionMetadataService,
        view_metadata_service_1.ViewMetadataService,
        email_template_service_1.EmailTemplateService,
        sms_template_service_1.SmsTemplateService,
        list_of_values_service_1.ListOfValuesService,
        permission_metadata_repository_1.PermissionMetadataRepository,
        solid_registry_1.SolidRegistry,
        setting_service_1.SettingService,
        setting_repository_1.SettingRepository,
        security_rule_repository_1.SecurityRuleRepository,
        system_fields_seeder_service_1.SystemFieldsSeederService,
        dashboard_repository_1.DashboardRepository,
        scheduled_job_repository_1.ScheduledJobRepository,
        saved_filters_repository_1.SavedFiltersRepository,
        typeorm_1.DataSource,
        model_sequence_repository_1.ModelSequenceRepository])
], ModuleMetadataSeederService);
//# sourceMappingURL=module-metadata-seeder.service.js.map