"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.addRuntimeGenerator = addRuntimeGenerator;
const tslib_1 = require("tslib");
const devkit_1 = require("@nx/devkit");
const path = tslib_1.__importStar(require("path"));
const utils_1 = require("../utils");
const dependency_config_1 = require("../dependency-config");
const add_application_1 = require("../add-application/add-application");
const add_visual_1 = require("../add-visual/add-visual");
async function getEnquirerPrompt() {
    const enquirer = await import('enquirer');
    // Handle both CommonJS and ESM exports
    return enquirer.prompt || enquirer.default?.prompt || enquirer;
}
async function promptForAddVisual() {
    const prompt = await getEnquirerPrompt();
    const response = await prompt({
        type: 'confirm',
        name: 'addVisual',
        message: 'Would you like to add a visual to this runtime?',
        initial: true,
    });
    return response.addVisual;
}
async function promptForAnalyticsAppId(existingValue) {
    if (existingValue !== undefined) {
        return existingValue;
    }
    const prompt = await getEnquirerPrompt();
    const response = await prompt({
        type: 'input',
        name: 'analyticsAppId',
        message: 'Provide the analytics app id (number). If you are not certain, leave it empty and later update the runtime constructor.',
        validate: (input) => {
            if (input === '')
                return true; // Allow empty
            const num = Number(input);
            return !isNaN(num) && Number.isInteger(num) ? true : 'Please enter a valid integer or leave empty';
        },
    });
    const value = response.analyticsAppId;
    return value === '' ? undefined : Number(value);
}
function updateTypesIndexExport(tree, runtimeName, basePath) {
    const indexPath = `${basePath}/src/index.ts`;
    if (!tree.exists(indexPath)) {
        throw new Error(`Index file not found at ${indexPath}`);
    }
    const currentContent = tree.read(indexPath, 'utf-8');
    if (!currentContent) {
        throw new Error(`Failed to read content from ${indexPath}`);
    }
    const exportLine = `export * from './lib/${runtimeName}-runtime';`;
    // Check if the export already exists
    if (currentContent.includes(exportLine)) {
        return; // Already exported
    }
    // Add the export at the end of the file
    const updatedContent = currentContent + '\n' + exportLine;
    tree.write(indexPath, updatedContent);
}
async function addRuntimeGenerator(tree, options) {
    // Normalize consumer option - Nx list prompts may return string labels instead of boolean values
    let isExternal = options?.consumer === 'external' ? true : false;
    // Validate and read .unisphere configuration
    const unisphereConfig = (0, utils_1.validateUnisphereConfig)(tree);
    // Validate dependencies
    const selectedDependencies = options.dependencies || [];
    // Extract environment variables
    const companyName = unisphereConfig.company;
    const widgetName = unisphereConfig.name;
    // Validate and correct runtime naming for React/DS dependencies
    let userInputRuntimeName = (0, devkit_1.names)(options.name).fileName;
    // Find types package (or fallback to core)
    const typesPackageInfo = (0, utils_1.findTypesOrCorePackageInfo)(tree);
    // Prompt for analyticsAppId only if isExternal is true
    const analyticsAppId = isExternal
        ? await promptForAnalyticsAppId(options.analyticsAppId)
        : options.analyticsAppId;
    // Prepare template variables
    const templateVariables = {
        companyName,
        analyticsAppId,
        typesAlias: typesPackageInfo.alias,
        // Add all name transformations
        ...(0, utils_1.createNameTransforms)(userInputRuntimeName, 'runtimeName'),
        ...(0, utils_1.createNameTransforms)(widgetName, 'widgetName'),
        tmpl: '',
    };
    const projectRoot = `unisphere/runtimes/${userInputRuntimeName}`;
    // Check if the runtime already exists
    if (tree.exists(projectRoot)) {
        throw new Error(`Runtime "${userInputRuntimeName}" already exists at ${projectRoot}.\n` +
            'Please choose a different runtime name or remove the existing runtime first.');
    }
    // Check if the runtime types file already exists in types/core package
    const runtimeTypesPath = `${typesPackageInfo.basePath}/src/lib/${userInputRuntimeName}-runtime/runtime-types.ts`;
    if (tree.exists(runtimeTypesPath)) {
        const packageName = typesPackageInfo.hasTypesPackage ? 'types' : 'core';
        throw new Error(`Runtime types file "${userInputRuntimeName}-runtime/runtime-types.ts" already exists in ${packageName} package.\n` +
            'Please choose a different runtime name or remove the existing file first.');
    }
    // Generate files from templates for the runtime
    (0, devkit_1.generateFiles)(tree, path.join(__dirname, 'templates/new-runtime'), projectRoot, templateVariables);
    // Generate the runtime types file in the types/core package using template
    (0, devkit_1.generateFiles)(tree, path.join(__dirname, 'templates/types-templates'), `${typesPackageInfo.basePath}/src/lib`, templateVariables);
    // Update types package index.ts to export the new runtime types
    updateTypesIndexExport(tree, userInputRuntimeName, typesPackageInfo.basePath);
    // Update .unisphere configuration
    (0, utils_1.updateUnisphereConfig)(tree, 'runtimes', userInputRuntimeName, {
        sourceRoot: `unisphere/runtimes/${userInputRuntimeName}`,
        distributionChannel: 'unisphere',
    });
    // Update tsconfig.base.json with path mapping
    const runtimePathKey = `unisphere-runtime-${userInputRuntimeName}`;
    const runtimePathValue = `unisphere/runtimes/${userInputRuntimeName}/src/index.ts`;
    (0, utils_1.updateTsConfigPaths)(tree, runtimePathKey, runtimePathValue);
    // Prompt to add a visual to the new runtime
    const shouldAddVisual = await promptForAddVisual();
    let visualName = '';
    if (shouldAddVisual) {
        const visualTask = await (0, add_visual_1.addVisualGenerator)(tree, {
            runtimeName: userInputRuntimeName,
        });
        const visualResponse = await visualTask();
        visualName = visualResponse.visualName;
    }
    let applicationScriptName = '';
    // Handle internal usage - create dev application
    if (!!isExternal) {
        // Create a dev application without prompts
        const appTask = await (0, add_application_1.addApplicationGenerator)(tree, {
            name: `${userInputRuntimeName}-dev`,
            servingType: 'local-dev-playground',
            runtimeName: userInputRuntimeName,
            visualName,
            skipDynamicRuntimeVisualPrompt: true, // Skip the runtime/visual selection prompts since we already have the info
            dependencies: selectedDependencies, // Pass same dependencies as runtime
        });
        applicationScriptName = `serve:${userInputRuntimeName}-dev`;
        await appTask();
    }
    // Install selected dependencies
    (0, dependency_config_1.installSelectedDependencies)(tree, selectedDependencies);
    await (0, devkit_1.formatFiles)(tree);
    // Return a function that will be executed after all file operations are complete
    return () => {
        (0, devkit_1.installPackagesTask)(tree, true);
        devkit_1.logger.info('');
        devkit_1.logger.info('✅ Runtime generated successfully!');
        devkit_1.logger.info('');
        devkit_1.logger.info(`🚀 Runtime Name: ${userInputRuntimeName}`);
        devkit_1.logger.info(`📁 Location: ${projectRoot}`);
        devkit_1.logger.info(`Analytics App ID: ${analyticsAppId}`);
        devkit_1.logger.info(`🔧 Consumer: ${isExternal ? 'External' : 'Internal'}`);
        if (applicationScriptName) {
            devkit_1.logger.info('');
            devkit_1.logger.info('📦 Additional components created:');
            devkit_1.logger.info(`   • Dev Application: ${userInputRuntimeName}-dev`);
            devkit_1.logger.info(`.    📜 To run the dev application locally: npm run ${applicationScriptName}`);
        }
        devkit_1.logger.info('');
    };
}
exports.default = addRuntimeGenerator;
