"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = default_1;
const tslib_1 = require("tslib");
const devkit_1 = require("@nx/devkit");
const path = require("path");
function default_1(tree, schema) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        schema.entity = schema.entity !== undefined ? schema.entity : true;
        const normalizedNames = generateNameVariants(schema.name, 'entity');
        const normalizedModuleNames = generateNameVariants(schema.moduleName, 'module');
        const targetDir = (0, devkit_1.joinPathFragments)('libs', 'modules', // Ensure 'modules' is part of the path
        normalizedModuleNames.moduleFileName, 'src', 'lib', 'entities', normalizedNames.entityFileName);
        // Define the new menu item to add
        const newMenuItem = `
   {
     text: \`\${scope}.${normalizedNames.entityPropertyName}\`,
     path: '',
     icon: '${schema.icon || 'fa-light fa-default'}'
   },
`;
        // Process custom properties
        const propertyDefinitions = processProperties(schema);
        // Generate actual property code for the entity file
        const entityPropertiesCode = generateEntityProperties(propertyDefinitions);
        const entityColumnsCode = generateEntityColumns(propertyDefinitions);
        const layoutPropertiesCode = generateLayoutProperties(propertyDefinitions);
        const modelPropertiesCode = generateModelProperties(propertyDefinitions);
        const firstPropertyName = propertyDefinitions.length > 0 ? propertyDefinitions[0].name : 'name';
        const targetDirModule = (0, devkit_1.joinPathFragments)('libs', 'modules', normalizedModuleNames.moduleFileName);
        const entityFilePath = (0, devkit_1.joinPathFragments)(targetDir, `${normalizedNames.entityFileName}.entity.ts`);
        if (schema.entity !== false) {
            (0, devkit_1.generateFiles)(tree, path.join(__dirname, 'files'), targetDir, Object.assign(Object.assign(Object.assign(Object.assign({}, schema), normalizedModuleNames), normalizedNames), { entityPropertiesCode,
                entityColumnsCode,
                layoutPropertiesCode,
                modelPropertiesCode,
                firstPropertyName, tmpl: '' }));
        }
        else {
            // Remove the entity file from the generated files
            tree.delete(entityFilePath);
        }
        function generateNameVariants(baseName, prefix) {
            const formattedNames = (0, devkit_1.names)(baseName);
            //const capitalizedPrefix = prefix.charAt(0).toUpperCase() + prefix.slice(1);
            return {
                [`${prefix}Name`]: formattedNames.name,
                [`${prefix}ClassName`]: formattedNames.className,
                [`${prefix}PropertyName`]: formattedNames.propertyName,
                [`${prefix}FileName`]: formattedNames.fileName,
                [`${prefix}ConstantName`]: formattedNames.constantName,
                [`${prefix}HumanName`]: toSpacedString(formattedNames.name),
            };
        }
        function toSpacedString(str) {
            return str.replace(/([a-z0-9])([A-Z])/g, '$1 $2').toLowerCase();
        }
        function processProperties(schema) {
            // Handle both array and string inputs for backward compatibility
            let propNames = [];
            let dataTypes = [];
            let requiredProps = [];
            let colSpans = [];
            let orders = [];
            let enableSorts = [];
            let enableFilters = [];
            let enableInlineFilters = [];
            let inColumns = [];
            // Process properties
            if (Array.isArray(schema.properties)) {
                propNames = schema.properties;
            }
            else if (schema.properties === '_interactive_') {
                // This will be handled by the interactive prompt in NX
                // For now, use defaults
                propNames = ['name', 'title'];
            }
            else if (schema.properties) {
                propNames = schema.properties.split(',').map((p) => p.trim());
            }
            else {
                propNames = ['name', 'title'];
            }
            // Process data types
            if (Array.isArray(schema.dataTypes)) {
                dataTypes = schema.dataTypes;
            }
            else if (schema.dataTypes === '_interactive_') {
                // This will be handled by the interactive prompt in NX
                // For now, use string for all properties
                dataTypes = Array(propNames.length).fill('string');
            }
            else if (schema.dataTypes) {
                dataTypes = schema.dataTypes.split(',').map((t) => t.trim());
            }
            else {
                dataTypes = Array(propNames.length).fill('string');
            }
            // Ensure dataTypes has the same length as propNames
            while (dataTypes.length < propNames.length) {
                dataTypes.push('string');
            }
            // Process required properties
            if (Array.isArray(schema.required)) {
                requiredProps = schema.required;
            }
            else if (schema.required === '_all_') {
                requiredProps = [...propNames];
            }
            else if (schema.required === '_none_') {
                requiredProps = [];
            }
            else if (schema.required === '_interactive_') {
                // This will be handled by the interactive prompt in NX
                // For now, use first two properties as required
                requiredProps = propNames.slice(0, 2);
            }
            else if (schema.required) {
                requiredProps = schema.required.split(',').map((r) => r.trim());
            }
            else {
                requiredProps = propNames.slice(0, 2); // First two properties are required by default
            }
            // Process column spans
            if (Array.isArray(schema.colSpans)) {
                colSpans = schema.colSpans;
            }
            else if (schema.colSpans) {
                colSpans = schema.colSpans.split(',').map((c) => c.trim());
            }
            else {
                colSpans = Array(propNames.length).fill('6'); // Default column span is 6 (half of 12-column grid)
            }
            // Ensure colSpans has the same length as propNames
            while (colSpans.length < propNames.length) {
                colSpans.push('6');
            }
            // Process orders
            if (Array.isArray(schema.orders)) {
                orders = schema.orders;
            }
            else if (schema.orders) {
                orders = schema.orders.split(',').map((o) => o.trim());
            }
            else {
                // Default order is sequential starting from 1
                orders = propNames.map((_, index) => (index + 1).toString());
            }
            // Ensure orders has the same length as propNames
            while (orders.length < propNames.length) {
                orders.push((orders.length + 1).toString());
            }
            // Process enableSorts
            if (Array.isArray(schema.enableSorts)) {
                enableSorts = schema.enableSorts;
            }
            else if (schema.enableSorts) {
                enableSorts = schema.enableSorts.split(',').map((s) => s.trim());
            }
            else {
                enableSorts = Array(propNames.length).fill('true'); // Default is true
            }
            // Ensure enableSorts has the same length as propNames
            while (enableSorts.length < propNames.length) {
                enableSorts.push('true');
            }
            // Process enableFilters
            if (Array.isArray(schema.enableFilters)) {
                enableFilters = schema.enableFilters;
            }
            else if (schema.enableFilters) {
                enableFilters = schema.enableFilters.split(',').map((f) => f.trim());
            }
            else {
                enableFilters = Array(propNames.length).fill('true'); // Default is true
            }
            // Ensure enableFilters has the same length as propNames
            while (enableFilters.length < propNames.length) {
                enableFilters.push('true');
            }
            // Process enableInlineFilters
            if (Array.isArray(schema.enableInlineFilters)) {
                enableInlineFilters = schema.enableInlineFilters;
            }
            else if (schema.enableInlineFilters) {
                enableInlineFilters = schema.enableInlineFilters.split(',').map((f) => f.trim());
            }
            else {
                enableInlineFilters = Array(propNames.length).fill('false'); // Default is false
            }
            // Ensure enableInlineFilters has the same length as propNames
            while (enableInlineFilters.length < propNames.length) {
                enableInlineFilters.push('false');
            }
            // Process inColumns
            if (Array.isArray(schema.inColumns)) {
                inColumns = schema.inColumns;
            }
            else if (schema.inColumns) {
                inColumns = schema.inColumns.split(',').map((c) => c.trim());
            }
            else {
                inColumns = propNames.slice(0, 4).map(() => 'true'); // Default: first 4 properties in column
                if (propNames.length > 4) {
                    inColumns = [...inColumns, ...Array(propNames.length - 4).fill('false')];
                }
            }
            // Ensure inColumns has the same length as propNames
            while (inColumns.length < propNames.length) {
                inColumns.push('false');
            }
            return propNames.map((propName, index) => ({
                name: propName,
                dataType: dataTypes[index] || 'string',
                isRequired: requiredProps.includes(propName),
                colSpan: parseInt(colSpans[index] || '6', 10),
                order: parseInt(orders[index] || (index + 1).toString(), 10),
                enableSort: enableSorts[index] === 'true',
                enableFilter: enableFilters[index] === 'true',
                enableInlineFilter: enableInlineFilters[index] === 'true',
                inColumn: inColumns[index] === 'true',
            }));
        }
        function generateModelProperties(props) {
            return props.map((prop) => `  ${prop.name}: ${getTypeScriptType(prop.dataType)};`).join('\n');
        }
        function getTypeScriptType(dataType) {
            switch (dataType.toLowerCase()) {
                case 'number':
                case 'int':
                case 'integer':
                    return 'number';
                case 'boolean':
                case 'bool':
                    return 'boolean';
                case 'date':
                case 'datetime':
                    return 'Date';
                case 'object':
                    return 'any';
                case 'array':
                    return 'any[]';
                default:
                    return 'string';
            }
        }
        function generateEntityProperties(props) {
            return props
                .map((prop) => {
                // Use a different approach for the scope value
                const scopeValue = prop.name === 'name' || prop.name === 'title' ? 'common' : '${i18n}'; // Escape the $ character
                return `
      {
        name: '${prop.name}',
        title: \`t("${prop.name}", { scope: "${scopeValue}" })\`,
        groupId: 'section',
        options: {
          sort: {
            enabled: ${prop.enableSort},
          },
           filter: {
            advance: {
               enabled: ${prop.enableFilter},
            },
            inline: {
              enabled: ${prop.enableInlineFilter},
            },
          },
        },
        schema: {
          dataType: '${prop.dataType}',
          interface: {
            type: ${getWidgetType(prop.dataType)},
          },
        },${prop.isRequired
                    ? `
        validations: [
          {
            rule: 'required',
          },
        ],`
                    : ''}
      },`;
            })
                .join('\n');
        }
        function getWidgetType(dataType) {
            switch (dataType.toLowerCase()) {
                case 'number':
                case 'int':
                case 'integer':
                    return 'AXPWidgetsCatalog.number';
                case 'boolean':
                case 'bool':
                    return 'AXPWidgetsCatalog.checkbox';
                case 'date':
                    return 'AXPWidgetsCatalog.date';
                case 'datetime':
                    return 'AXPWidgetsCatalog.dateTime';
                case 'password':
                    return 'AXPWidgetsCatalog.password';
                case 'email':
                    return 'AXPWidgetsCatalog.email';
                case 'textarea':
                case 'longtext':
                    return 'AXPWidgetsCatalog.textarea';
                case 'html':
                    return 'AXPWidgetsCatalog.html';
                case 'select':
                case 'dropdown':
                    return 'AXPWidgetsCatalog.select';
                default:
                    return 'AXPWidgetsCatalog.text';
            }
        }
        function generateEntityColumns(props) {
            // Use properties marked as inColumn instead of just first 4
            const columnProps = props.filter((prop) => prop.inColumn !== false);
            return columnProps.map((prop) => `{ name: '${prop.name}' }`).join(', ');
        }
        function generateLayoutProperties(props) {
            // Sort properties by order
            const sortedProps = [...props].sort((a, b) => a.order - b.order);
            return sortedProps
                .map((prop) => `
            {
              name: '${prop.name}',
              layout: {
                positions: {
                  lg: {
                    colSpan: ${prop.colSpan},
                    order: ${prop.order},
                  },
                },
              },
            },`)
                .join('\n');
        }
        // Update const.ts with the new entity key
        const constFilePath = (0, devkit_1.joinPathFragments)(targetDirModule, 'src/lib/const.ts');
        if (tree.exists(constFilePath)) {
            if (tree.exists(constFilePath)) {
                const originalContent = tree.read(constFilePath, 'utf-8');
                // Construct the new entity object
                const newEntityContent = `
    ${normalizedNames.entityPropertyName}: {
      name: '${normalizedNames.entityClassName}',
      title: \`t("${normalizedNames.entityPropertyName}", { scope: "\${config.i18n}" })\`,
      titlePlural: \`t("${normalizedNames.entityPropertyName}Plural", { scope: "\${config.i18n}" })\`,
      icon: '${schema.icon || 'fa-light fa-default'}',
    },`;
                // Check if `entities` object already exists
                if (/entities:\s*\{[^}]*\}/.test(originalContent)) {
                    // Append the new entity inside the `entities` object
                    const newContent = originalContent.replace(/(entities:\s*\{)/, `$1${newEntityContent}`);
                    tree.write(constFilePath, newContent);
                }
                else {
                    // If `entities` doesn't exist, add it before closing `RootConfig`
                    const newContent = originalContent.replace(/RootConfig\s*=\s*\{([^}]*config,\s*module:[^}]*)\}/, `RootConfig = {$1, entities: {${newEntityContent}}}`);
                    tree.write(constFilePath, newContent);
                }
            }
        }
        // Append service provider to the existing module.ts file if it exists
        const moduleFilePath = (0, devkit_1.joinPathFragments)(targetDirModule, `src/lib/${normalizedModuleNames.moduleFileName}.module.ts`);
        // Define import and provider strings for the new entity
        const serviceImport = `import { AXM${normalizedNames.entityClassName}Service, AXM${normalizedNames.entityClassName}ServiceImpl } from './entities';`;
        const serviceProvider = `{
      provide: AXM${normalizedNames.entityClassName}Service,
      useClass: AXM${normalizedNames.entityClassName}ServiceImpl,
    }`;
        if (tree.exists(moduleFilePath)) {
            const originalContent = tree.read(moduleFilePath, 'utf-8');
            // Add the import if not already present
            const updatedImports = originalContent.includes(serviceImport)
                ? originalContent
                : originalContent.replace(/(@NgModule\(\{)/, `${serviceImport}\n$1`);
            // Add the provider to the providers array if not already present
            const updatedProviders = updatedImports.includes(serviceProvider)
                ? updatedImports
                : updatedImports.replace(/providers:\s*\[/, `providers: [${serviceProvider}, `);
            // Write the updated content back to the module file
            tree.write(moduleFilePath, updatedProviders);
        }
        // Append new menu item to `children` array in `menu.provider.ts`
        const menuProviderFilePath = (0, devkit_1.joinPathFragments)(targetDirModule, 'src/lib/menu.provider.ts');
        if (tree.exists(menuProviderFilePath)) {
            const originalContent = tree.read(menuProviderFilePath, 'utf-8');
            // Find the placeholder in the children array and add the new menu item
            const updatedContent = originalContent.replace(/children:\s*\[\s*<%= menuItems %>\s*\]/, `children: [${newMenuItem}<%= menuItems %>]`);
            // Write the updated content back to the `menu.provider.ts` file
            tree.write(menuProviderFilePath, updatedContent);
        }
        const indexFilePath = (0, devkit_1.joinPathFragments)(targetDirModule, 'src', 'lib', 'entities', 'index.ts');
        // Define the new export line
        const newExportLine = `export * from './${normalizedNames.entityFileName}';\n`;
        // Check if index.ts exists and append the new export line
        if (tree.exists(indexFilePath)) {
            const originalContent = tree.read(indexFilePath, 'utf-8');
            const updatedContent = originalContent.includes(newExportLine)
                ? originalContent
                : `${originalContent}${newExportLine}`;
            tree.write(indexFilePath, updatedContent);
        }
        else {
            // If index.ts does not exist, create it with the new export line
            tree.write(indexFilePath, newExportLine);
        }
    });
}
//# sourceMappingURL=generator.js.map