"use strict";
/**
 * Frontend Module Generator
 *
 * Main orchestrator for generating frontend modules from JSON schema.
 */
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 __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;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateWebModule = generateWebModule;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const templates_1 = require("./templates");
const field_mapper_1 = require("./transformers/field-mapper");
const i18n_generator_1 = require("./transformers/i18n-generator");
const import_resolver_1 = require("./transformers/import-resolver");
const name_transformer_1 = require("./transformers/name-transformer");
const parent_detector_1 = require("./transformers/parent-detector");
const relationship_resolver_1 = require("./transformers/relationship-resolver");
const utils_1 = require("./utils");
const json_schema_validator_1 = require("./validators/json-schema-validator");
/**
 * Generate all frontend module files from JSON schema
 *
 * @param options - Generator options
 * @returns True if generation succeeded
 */
async function generateWebModule(options) {
    const { jsonPath, dryRun = false, force = false, noRegister = false } = options;
    console.log(`\n🔧 Frontend Module Generator`);
    console.log(`   JSON Schema: ${jsonPath}`);
    console.log(`   Dry Run: ${dryRun}`);
    console.log(`   Force: ${force}`);
    console.log(`   No Register: ${noRegister}`);
    // Step 1: Validate JSON schema
    console.log("\n📋 Validating JSON schema...");
    const validation = (0, json_schema_validator_1.parseAndValidate)(jsonPath);
    if (!(0, json_schema_validator_1.validationPassed)(validation)) {
        console.error("\n❌ Validation failed:");
        validation.errors.forEach((e) => console.error(`   - ${e}`));
        return false;
    }
    if (validation.warnings.length > 0) {
        console.log("\n⚠️  Validation warnings (non-blocking):");
        validation.warnings.forEach((w) => console.log(`   - ${w}`));
    }
    const schema = validation.data;
    console.log(`   ✅ Schema valid: ${schema.moduleName}`);
    // Step 2: Build template data
    console.log("\n🔨 Building template data...");
    const templateData = buildTemplateData(schema);
    console.log(`   Module: ${templateData.names.pascalCase}`);
    console.log(`   Target: ${templateData.targetDir}`);
    console.log(`   Extends Content: ${templateData.extendsContent}`);
    console.log(`   Fields: ${templateData.fields.length}`);
    console.log(`   Relationships: ${templateData.relationships.length}`);
    // Step 3: Generate all files
    console.log("\n📝 Generating files...");
    const files = generateAllFiles(templateData, schema);
    console.log(`   Generated ${files.length} file templates`);
    // Step 4: Determine web base path
    const webBasePath = findWebBasePath(jsonPath);
    if (!webBasePath) {
        console.error("\n❌ Could not determine web app base path");
        return false;
    }
    console.log(`   Web base path: ${webBasePath}`);
    // Step 5: Write files
    console.log("\n💾 Writing files...");
    const results = (0, utils_1.writeFiles)(files, { dryRun, force });
    (0, utils_1.printResults)(results);
    // Step 6: Update Bootstrapper (unless --no-register)
    if (!noRegister) {
        console.log("\n🔧 Updating Bootstrapper.ts...");
        const bootstrapResult = (0, utils_1.updateBootstrapper)(templateData, webBasePath, dryRun);
        console.log(`   ${bootstrapResult.success ? "✅" : "❌"} ${bootstrapResult.message}`);
    }
    // Step 7: Update i18n for all languages (unless --no-register)
    if (!noRegister) {
        const languages = schema.languages || ["en"];
        console.log(`\n🌐 Updating i18n for ${languages.length} language(s)...`);
        for (const language of languages) {
            const i18nResult = (0, utils_1.updateI18n)(templateData, webBasePath, language, dryRun);
            console.log(`   ${i18nResult.success ? "✅" : "❌"} ${i18nResult.message}`);
        }
    }
    console.log("\n✅ Generation complete!");
    if (dryRun) {
        console.log("\n📝 This was a dry run. No files were actually written.");
        console.log("   Remove --dry-run to generate files.");
    }
    return true;
}
/**
 * Build template data from JSON schema
 */
function buildTemplateData(schema) {
    const names = (0, name_transformer_1.transformNames)(schema.moduleName, schema.endpointName);
    const targetDir = schema.targetDir;
    const extendsContent = (0, parent_detector_1.detectExtendsContent)(schema.fields, schema.extendsContent);
    // Map fields
    const allFields = (0, field_mapper_1.mapFields)(schema.fields, names.camelCase);
    // Get inherited fields to filter out for forms (Content fields are handled specially)
    const inheritedFields = extendsContent ? ["name", "tldr", "abstract", "content"] : [];
    const fields = (0, field_mapper_1.filterInheritedFields)(allFields, inheritedFields);
    // Resolve relationships
    const relationships = (0, relationship_resolver_1.resolveRelationships)(schema.relationships);
    const relationshipServiceMethods = (0, relationship_resolver_1.generateServiceMethods)(relationships);
    // Build imports
    const imports = (0, import_resolver_1.buildImportStatements)(relationships, extendsContent);
    // Generate i18n keys
    const i18nKeys = (0, i18n_generator_1.generateI18nKeys)(names, fields, relationships);
    // Build table field names
    const tableFieldNames = buildTableFieldNames(schema, extendsContent);
    return {
        names,
        moduleId: schema.moduleId,
        endpoint: schema.endpointName,
        targetDir,
        extendsContent,
        fields: allFields, // Keep all fields for interface generation
        relationships,
        i18nKeys,
        imports,
        tableFieldNames,
        relationshipServiceMethods,
    };
}
/**
 * Build field names for table display
 */
function buildTableFieldNames(schema, extendsContent) {
    const fieldNames = [`${(0, name_transformer_1.toCamelCase)(schema.moduleName)}Id`];
    // Add name for all modules
    fieldNames.push("name");
    // Add authors for content modules
    if (extendsContent) {
        fieldNames.push("authors");
    }
    // Add custom fields (excluding certain ones)
    schema.fields.forEach((f) => {
        if (!["id", "name", "tldr", "abstract", "content", "createdAt", "updatedAt"].includes(f.name)) {
            fieldNames.push(f.name);
        }
    });
    // Add standard date fields
    fieldNames.push("createdAt", "updatedAt");
    return fieldNames;
}
/**
 * Generate all module files
 */
function generateAllFiles(data, schema) {
    const files = [];
    const paths = (0, import_resolver_1.buildFilePaths)(data, findWebBasePath(""));
    // Data layer (4 files)
    files.push({
        path: paths.interface,
        content: (0, templates_1.generateInterfaceTemplate)(data),
        type: "data",
    });
    files.push({
        path: paths.model,
        content: (0, templates_1.generateModelTemplate)(data),
        type: "data",
    });
    files.push({
        path: paths.service,
        content: (0, templates_1.generateServiceTemplate)(data),
        type: "data",
    });
    files.push({
        path: paths.fields,
        content: (0, templates_1.generateFieldsTemplate)(data),
        type: "data",
    });
    // Form components (4 files)
    files.push({
        path: paths.editor,
        content: (0, templates_1.generateEditorTemplate)(data),
        type: "component",
    });
    files.push({
        path: paths.deleter,
        content: (0, templates_1.generateDeleterTemplate)(data),
        type: "component",
    });
    files.push({
        path: paths.selector,
        content: (0, templates_1.generateSelectorTemplate)(data),
        type: "component",
    });
    files.push({
        path: paths.multiSelector,
        content: (0, templates_1.generateMultiSelectorTemplate)(data),
        type: "component",
    });
    // Display components (4-5 files)
    files.push({
        path: paths.list,
        content: (0, templates_1.generateListTemplate)(data),
        type: "component",
    });
    files.push({
        path: paths.details,
        content: (0, templates_1.generateDetailsTemplate)(data),
        type: "component",
    });
    // Content component only for Content-extending modules
    const contentTemplate = (0, templates_1.generateContentTemplate)(data);
    if (contentTemplate) {
        files.push({
            path: paths.content,
            content: contentTemplate,
            type: "component",
        });
    }
    files.push({
        path: paths.container,
        content: (0, templates_1.generateContainerTemplate)(data),
        type: "component",
    });
    files.push({
        path: paths.listContainer,
        content: (0, templates_1.generateListContainerTemplate)(data),
        type: "component",
    });
    // Context & hooks (2 files)
    files.push({
        path: paths.context,
        content: (0, templates_1.generateContextTemplate)(data),
        type: "context",
    });
    files.push({
        path: paths.tableHook,
        content: (0, templates_1.generateTableHookTemplate)(data),
        type: "hook",
    });
    // Module (1 file)
    files.push({
        path: paths.module,
        content: (0, templates_1.generateModuleTemplate)(data),
        type: "module",
    });
    // Pages (2 files)
    files.push({
        path: paths.listPage,
        content: (0, templates_1.generateListPageTemplate)(data),
        type: "page",
    });
    files.push({
        path: paths.detailPage,
        content: (0, templates_1.generateDetailPageTemplate)(data),
        type: "page",
    });
    return files;
}
/**
 * Find the web app base path from the JSON path
 * Assumes JSON is in /structure folder and web app is in /apps/web
 */
function findWebBasePath(jsonPath) {
    // Try to find apps/web relative to current working directory
    const cwd = process.cwd();
    // Check if we're in the monorepo root
    if (fs.existsSync(path.join(cwd, "apps/web"))) {
        return cwd;
    }
    // Check if we're in packages/nextjs-jsonapi
    if (fs.existsSync(path.join(cwd, "../../apps/web"))) {
        return path.join(cwd, "../..");
    }
    // Try to derive from jsonPath
    if (jsonPath) {
        const resolved = path.resolve(jsonPath);
        // Look for monorepo root by finding apps/web
        let current = path.dirname(resolved);
        for (let i = 0; i < 10; i++) {
            if (fs.existsSync(path.join(current, "apps/web"))) {
                return current;
            }
            const parent = path.dirname(current);
            if (parent === current)
                break;
            current = parent;
        }
    }
    // Default to current directory
    return cwd;
}
exports.default = generateWebModule;
//# sourceMappingURL=generator.js.map