"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = update;
const devkit_1 = require("@nx/devkit");
const path_1 = require("path");
const dotenv_1 = require("dotenv");
const DEFINE_PLUGIN_IMPORT = "const { DefinePlugin } = require('webpack');";
/**
 * Detect the type of an env value
 */
function detectType(value) {
    if (value === 'true' || value === 'false') {
        return 'boolean';
    }
    if (!isNaN(Number(value)) && value !== '') {
        return 'number';
    }
    return 'string';
}
/**
 * Parse .env file content using dotenv and add type detection
 */
function parseEnvFile(content) {
    const parsed = (0, dotenv_1.parse)(Buffer.from(content));
    return Object.entries(parsed).map(([key, value]) => ({
        key,
        value: value || '',
        type: detectType(value || ''),
    }));
}
/**
 * Generate DefinePlugin block with env variables
 */
function generateDefinePluginBlock(envVars) {
    if (envVars.length === 0) {
        return `new DefinePlugin({
      // Add your environment variables here
      // Example: 'process.env.API_URL': JSON.stringify(process.env.API_URL),
    }),`;
    }
    const entries = envVars.map(({ key, type }) => {
        if (type === 'boolean') {
            return `      'process.env.${key}': process.env.${key} === 'true',`;
        }
        else if (type === 'number') {
            return `      'process.env.${key}': Number(process.env.${key}),`;
        }
        else {
            return `      'process.env.${key}': JSON.stringify(process.env.${key}),`;
        }
    });
    return `new DefinePlugin({
${entries.join('\n')}
    }),`;
}
/**
 * Generate .env-template content from parsed env variables
 */
function generateEnvTemplate(envVars) {
    const header = `# Environment variables template
# Copy this file to .env and fill in the values
# Do not commit .env to version control

`;
    if (envVars.length === 0) {
        return header + `# Example:
# API_URL=https://api.example.com
`;
    }
    const entries = envVars.map(({ key, value, type }) => {
        const typeComment = type !== 'string' ? ` # ${type}` : '';
        return `${key}=${value}${typeComment}`;
    });
    return header + entries.join('\n') + '\n';
}
/**
 * Merge env variables from two sources, preferring values from the first source
 */
function mergeEnvVars(primary, secondary) {
    const merged = new Map();
    // Add secondary first (will be overwritten by primary)
    for (const envVar of secondary) {
        merged.set(envVar.key, envVar);
    }
    // Add primary (overwrites secondary)
    for (const envVar of primary) {
        merged.set(envVar.key, envVar);
    }
    return Array.from(merged.values());
}
async function update(tree) {
    devkit_1.logger.info('🔄 Adding DefinePlugin to application webpack configs');
    try {
        // Read .unisphere config
        if (!tree.exists('.unisphere')) {
            devkit_1.logger.warn('⚠️ No .unisphere file found, skipping');
            return;
        }
        const unisphereConfig = (0, devkit_1.readJson)(tree, '.unisphere');
        const applications = unisphereConfig.elements?.applications;
        if (!applications || Object.keys(applications).length === 0) {
            devkit_1.logger.info('ℹ️ No applications found, skipping');
            return;
        }
        let webpackUpdatedCount = 0;
        let envTemplateCreatedCount = 0;
        for (const [appName, appConfig] of Object.entries(applications)) {
            const appPath = appConfig.sourceRoot;
            const webpackPath = (0, path_1.join)(appPath, 'webpack.config.js');
            const envPath = (0, path_1.join)(appPath, '.env');
            const envTemplatePath = (0, path_1.join)(appPath, '.env-template');
            // Skip if neither .env nor .env-template exists - don't touch anything
            const hasEnv = tree.exists(envPath);
            const hasEnvTemplate = tree.exists(envTemplatePath);
            if (!hasEnv && !hasEnvTemplate) {
                devkit_1.logger.info(`ℹ️ ${appName}: No .env or .env-template found, skipping`);
                continue;
            }
            // Parse env files and merge (template values take priority)
            let envVars = [];
            let envVarsFromEnv = [];
            let envVarsFromTemplate = [];
            if (hasEnv) {
                const envContent = tree.read(envPath, 'utf-8') || '';
                envVarsFromEnv = parseEnvFile(envContent);
                devkit_1.logger.info(`ℹ️ ${appName}: Found ${envVarsFromEnv.length} env variable(s) in .env`);
            }
            if (hasEnvTemplate) {
                const templateContent = tree.read(envTemplatePath, 'utf-8') || '';
                envVarsFromTemplate = parseEnvFile(templateContent);
                devkit_1.logger.info(`ℹ️ ${appName}: Found ${envVarsFromTemplate.length} env variable(s) in .env-template`);
            }
            // Merge: .env-template values take priority over .env values
            envVars = mergeEnvVars(envVarsFromTemplate, envVarsFromEnv);
            devkit_1.logger.info(`ℹ️ ${appName}: Using ${envVars.length} merged env variable(s)`);
            // Handle webpack.config.js
            if (tree.exists(webpackPath)) {
                let webpackContent = tree.read(webpackPath, 'utf-8') || '';
                let updated = false;
                // Check if DefinePlugin is already imported
                if (!webpackContent.includes('DefinePlugin')) {
                    // Add DefinePlugin import after NxReactWebpackPlugin import
                    if (webpackContent.includes("require('@nx/react/webpack-plugin')")) {
                        webpackContent = webpackContent.replace("require('@nx/react/webpack-plugin');", `require('@nx/react/webpack-plugin');\n${DEFINE_PLUGIN_IMPORT}`);
                    }
                    else if (webpackContent.includes("require('@nx/webpack/app-plugin')")) {
                        // Fallback: add after NxAppWebpackPlugin import
                        webpackContent = webpackContent.replace("require('@nx/webpack/app-plugin');", `require('@nx/webpack/app-plugin');\n${DEFINE_PLUGIN_IMPORT}`);
                    }
                    // Add DefinePlugin to plugins array with env variables
                    const definePluginBlock = generateDefinePluginBlock(envVars);
                    if (webpackContent.includes('plugins: [')) {
                        webpackContent = webpackContent.replace('plugins: [', `plugins: [\n    ${definePluginBlock}`);
                    }
                    updated = true;
                    devkit_1.logger.info(`✅ ${appName}: Added DefinePlugin to webpack.config.js with ${envVars.length} variable(s)`);
                }
                else {
                    // DefinePlugin exists - replace it entirely with variables from .env
                    // Find the DefinePlugin block - match opening and find balanced closing
                    const defineStartMatch = webpackContent.match(/new DefinePlugin\(\{/);
                    if (defineStartMatch && defineStartMatch.index !== undefined) {
                        const startIndex = defineStartMatch.index;
                        let braceCount = 0;
                        let endIndex = startIndex;
                        let foundStart = false;
                        // Find the balanced closing })
                        for (let i = startIndex; i < webpackContent.length; i++) {
                            const char = webpackContent[i];
                            if (char === '{') {
                                braceCount++;
                                foundStart = true;
                            }
                            else if (char === '}') {
                                braceCount--;
                                if (foundStart && braceCount === 0) {
                                    // Found the closing }, now check for )
                                    if (webpackContent[i + 1] === ')') {
                                        endIndex = i + 2; // Include the )
                                        break;
                                    }
                                }
                            }
                        }
                        const existingBlock = webpackContent.substring(startIndex, endIndex);
                        // Generate new DefinePlugin block from env vars
                        const newBlock = generateDefinePluginBlock(envVars);
                        // Remove trailing comma from generateDefinePluginBlock output
                        const newBlockWithoutComma = newBlock.replace(/,\s*$/, '');
                        webpackContent = webpackContent.replace(existingBlock, newBlockWithoutComma);
                        updated = true;
                        devkit_1.logger.info(`✅ ${appName}: Replaced DefinePlugin with ${envVars.length} variable(s) from .env`);
                    }
                    else {
                        devkit_1.logger.warn(`⚠️ ${appName}: Could not find DefinePlugin block to update`);
                    }
                }
                if (updated) {
                    tree.write(webpackPath, webpackContent);
                    webpackUpdatedCount++;
                }
            }
            else {
                devkit_1.logger.info(`ℹ️ ${appName}: No webpack.config.js found, skipping`);
            }
            // Create or update .env-template with merged variables
            const templateKeys = new Set(envVarsFromTemplate.map((v) => v.key));
            const hasNewVarsFromEnv = envVarsFromEnv.some((v) => !templateKeys.has(v.key));
            if (!hasEnvTemplate) {
                // Create new .env-template from .env variables
                const envTemplateContent = generateEnvTemplate(envVars);
                tree.write(envTemplatePath, envTemplateContent);
                devkit_1.logger.info(`✅ ${appName}: Created .env-template`);
                envTemplateCreatedCount++;
            }
            else if (hasEnv && hasNewVarsFromEnv) {
                // Update .env-template with merged variables (new vars from .env)
                const envTemplateContent = generateEnvTemplate(envVars);
                tree.write(envTemplatePath, envTemplateContent);
                devkit_1.logger.info(`✅ ${appName}: Updated .env-template with new variables from .env`);
                envTemplateCreatedCount++;
            }
            else {
                devkit_1.logger.info(`✅ ${appName}: .env-template already up to date`);
            }
        }
        devkit_1.logger.info(`\n✅ Done: ${webpackUpdatedCount} webpack configs updated, ${envTemplateCreatedCount} .env-template files created`);
    }
    catch (error) {
        devkit_1.logger.error(`❌ Failed to update webpack configs: ${error?.message || 'Unknown error'}`);
        throw error;
    }
}
