"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 __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 __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.addCommand = addCommand;
const inquirer_1 = __importDefault(require("inquirer"));
const chalk_1 = __importDefault(require("chalk"));
const ora_1 = __importDefault(require("ora"));
const path_1 = __importDefault(require("path"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const config_1 = require("../utils/config");
const registry_1 = require("../utils/registry");
const dependencies_1 = require("../utils/dependencies");
const transformers_1 = require("../utils/transformers");
const projectAliases_1 = require("../utils/projectAliases");
const aliasManager_1 = require("../utils/aliasManager");
// Generate a unique filename by adding (1), (2), etc. suffix
function generateUniqueFilename(filePath) {
    const dir = path_1.default.dirname(filePath);
    const ext = path_1.default.extname(filePath);
    const nameWithoutExt = path_1.default.basename(filePath, ext);
    let counter = 1;
    let newPath = filePath;
    while (fs_extra_1.default.pathExistsSync(newPath)) {
        const newName = `${nameWithoutExt} (${counter})${ext}`;
        newPath = path_1.default.join(dir, newName);
        counter++;
    }
    return newPath;
}
// Create essential files that components might need
async function createComponentEssentials(componentDir, componentName) {
    // Create index.ts if it doesn't exist
    const indexPath = path_1.default.join(componentDir, 'index.ts');
    if (!await fs_extra_1.default.pathExists(indexPath)) {
        const indexContent = `export { default } from './${componentName}';
export * from './${componentName}';
`;
        await fs_extra_1.default.writeFile(indexPath, indexContent);
    }
    // For FormBuilder, ensure all sub-components are properly structured
    if (componentName.toLowerCase() === 'formbuilder') {
        const componentsDir = path_1.default.join(componentDir, 'components');
        await fs_extra_1.default.ensureDir(componentsDir);
        // Ensure properties and ui_wrappers directories exist
        await fs_extra_1.default.ensureDir(path_1.default.join(componentsDir, 'properties'));
        await fs_extra_1.default.ensureDir(path_1.default.join(componentsDir, 'ui_wrappers'));
    }
    // For FormTheme, ensure components directory exists
    if (componentName.toLowerCase() === 'formtheme') {
        const componentsDir = path_1.default.join(componentDir, 'components');
        await fs_extra_1.default.ensureDir(componentsDir);
    }
}
async function addCommand(components, options = {}) {
    const cwd = path_1.default.resolve(options.cwd || process.cwd());
    // Check if project is initialized, if not, initialize it automatically
    let config = await (0, config_1.getConfig)(cwd);
    if (!config) {
        // Import and run init command
        const { initCommand } = await Promise.resolve().then(() => __importStar(require('./init')));
        await initCommand({ yes: true, cwd });
        // Get the config after initialization
        config = await (0, config_1.getConfig)(cwd);
        if (!config) {
            process.exit(1);
        }
    }
    // Get or ask for base path - always ask if not set
    let basePath = config.basePath || options.path || '';
    if (!basePath) {
        const { basePathInput } = await inquirer_1.default.prompt([
            {
                type: 'input',
                name: 'basePathInput',
                message: 'What should be the base path for the component?',
                default: 'src/',
                validate: (input) => {
                    if (!input.trim())
                        return 'Base path cannot be empty';
                    return true;
                },
                filter: (input) => {
                    return input.trim().replace(/\/$/, '') + '/';
                }
            },
        ]);
        basePath = basePathInput;
        // Update config with base path
        config.basePath = basePath;
        const { writeConfig } = await Promise.resolve().then(() => __importStar(require('../utils/config')));
        await writeConfig(cwd, config);
    }
    // Ensure basePath ends with /
    if (!basePath.endsWith('/')) {
        basePath = basePath + '/';
    }
    // Get existing project aliases
    const projectAliases = await (0, projectAliases_1.getProjectAliases)(cwd);
    const resolvedConfig = await (0, config_1.resolveConfigPaths)(cwd, config);
    // If no components specified, show interactive selection
    if (components.length === 0) {
        const availableComponents = await (0, registry_1.getComponentList)();
        if (availableComponents.length === 0) {
            return;
        }
        const { selectedComponents } = await inquirer_1.default.prompt([
            {
                type: 'checkbox',
                name: 'selectedComponents',
                message: 'Select components to add:',
                choices: availableComponents.map(comp => ({
                    name: `${comp.name} - ${comp.description}`,
                    value: comp.name,
                })),
            },
        ]);
        if (selectedComponents.length === 0) {
            return;
        }
        components = selectedComponents;
    }
    const spinner = (0, ora_1.default)('Resolving components...').start();
    try {
        // Resolve all components and their dependencies
        const allComponents = new Map();
        const allDependencies = new Set();
        for (const componentName of components) {
            const resolvedComponents = await (0, registry_1.resolveComponentDependencies)(componentName);
            if (resolvedComponents.length === 0) {
                spinner.fail(`Component "${componentName}" not found.`);
                const available = await (0, registry_1.getComponentList)();
                available.forEach(comp => console.log(chalk_1.default.gray(`  • ${comp.name}`)));
                process.exit(1);
            }
            resolvedComponents.forEach((comp) => {
                allComponents.set(comp.name.toLowerCase(), comp);
                comp.dependencies.forEach((dep) => allDependencies.add(dep));
            });
        }
        const componentsToInstall = Array.from(allComponents.values());
        spinner.text = 'Checking existing files...';
        // Get supporting files once for reuse
        const supportingFiles = (0, registry_1.getAllSupportingFiles)();
        // Check for existing files under base path
        const existingFiles = [];
        const existingFilesAbsolute = [];
        // Check component files
        for (const component of componentsToInstall) {
            const componentBaseDir = path_1.default.resolve(cwd, basePath, component.name);
            for (const file of component.files) {
                const filePath = file.dir
                    ? path_1.default.resolve(componentBaseDir, file.dir, file.name)
                    : path_1.default.resolve(componentBaseDir, file.name);
                if (await fs_extra_1.default.pathExists(filePath)) {
                    existingFiles.push(path_1.default.relative(cwd, filePath));
                    existingFilesAbsolute.push(filePath); // Already resolved, no need to resolve again
                }
            }
        }
        // Check supporting files (excluding mocks)
        const basePathDir = path_1.default.resolve(cwd, basePath);
        for (const [dirName, files] of Object.entries(supportingFiles)) {
            // Skip mocks folder
            if (dirName === 'mocks') {
                continue;
            }
            for (const file of files) {
                const filePath = path_1.default.resolve(basePathDir, file.name);
                if (await fs_extra_1.default.pathExists(filePath)) {
                    existingFiles.push(path_1.default.relative(cwd, filePath));
                    existingFilesAbsolute.push(filePath);
                }
            }
        }
        // Handle dry-run mode
        if (options.dryRun) {
            spinner.stop();
            console.log(chalk_1.default.blue('\n🔍 Dry run mode - showing what would be installed:\n'));
            console.log(chalk_1.default.green('📦 Components to install:'));
            componentsToInstall.forEach(comp => {
                console.log(chalk_1.default.green(`  ✓ ${comp.name}`));
            });
            if (existingFiles.length > 0) {
                console.log(chalk_1.default.yellow('\n⚠️ Files that already exist (would be created with (1), (2), etc. suffix if you choose not to overwrite):'));
                existingFiles.forEach(file => console.log(chalk_1.default.gray(`  • ${file}`)));
            }
            if (allDependencies.size > 0) {
                console.log(chalk_1.default.blue('\n📚 Dependencies that would be installed:'));
                Array.from(allDependencies).forEach(dep => {
                    console.log(chalk_1.default.blue(`  • ${dep}`));
                });
            }
            console.log(chalk_1.default.gray('\n💡 Run without --dry-run to actually install these components'));
            return;
        }
        let shouldCreateWithSuffix = false;
        if (existingFiles.length > 0 && !options.overwrite && !options.yes) {
            spinner.stop();
            console.log(chalk_1.default.yellow('\n⚠️ The following files already exist:'));
            existingFiles.forEach(file => console.log(chalk_1.default.gray(`  • ${file}`)));
            const { proceed } = await inquirer_1.default.prompt([
                {
                    type: 'confirm',
                    name: 'proceed',
                    message: 'Do you want to overwrite these files?',
                    default: false,
                },
            ]);
            if (!proceed) {
                shouldCreateWithSuffix = true;
                console.log(chalk_1.default.blue('\n📦 Continuing with installation using unique filenames...'));
                console.log(chalk_1.default.gray(`   Existing files will be preserved, new files will have (1), (2), etc. suffix`));
            }
            spinner.start('Installing components...');
        }
        else {
            spinner.text = 'Installing components...';
        }
        // Install components under base path, preserving directory structure
        for (const component of componentsToInstall) {
            // Use base path + component name (e.g., src/formbuilder/)
            const componentBaseDir = path_1.default.resolve(cwd, basePath, component.name);
            // Create the main component directory
            await fs_extra_1.default.ensureDir(componentBaseDir);
            // Create all required directories first, preserving structure
            for (const dir of component.directories) {
                const dirPath = path_1.default.join(componentBaseDir, dir.path);
                await fs_extra_1.default.ensureDir(dirPath);
            }
            // Install files with proper directory structure under base path
            for (const file of component.files) {
                let filePath;
                if (file.dir) {
                    // File is in a subdirectory - preserve structure
                    filePath = path_1.default.resolve(componentBaseDir, file.dir, file.name);
                }
                else {
                    // File is in the root component directory
                    filePath = path_1.default.resolve(componentBaseDir, file.name);
                }
                // If file exists and user chose not to overwrite, generate unique filename
                if (shouldCreateWithSuffix && await fs_extra_1.default.pathExists(filePath)) {
                    filePath = generateUniqueFilename(filePath);
                    console.log(chalk_1.default.blue(`📝 Creating with unique name: ${path_1.default.relative(cwd, filePath)}`));
                }
                // Ensure the directory exists before writing the file
                await fs_extra_1.default.ensureDir(path_1.default.dirname(filePath));
                // Transform imports to use existing project aliases
                const transformedContent = (0, transformers_1.transformImports)(file.content, { ...resolvedConfig, projectAliases, basePath });
                await fs_extra_1.default.writeFile(filePath, transformedContent);
                console.log(chalk_1.default.green(`✓ Created: ${path_1.default.relative(cwd, filePath)}`));
            }
            // Create any missing essential files for this component
            await createComponentEssentials(componentBaseDir, component.name);
            // Create aliases in vite.config and tsconfig.json based on actual file locations
            await (0, aliasManager_1.createAliasesFromBasePath)(cwd, basePath, component.name);
        }
        // Install supporting files (constants, utils, hooks, assets, types) under basePath
        // Note: mocks folder is excluded from installation
        spinner.text = 'Installing supporting files...';
        for (const [dirName, files] of Object.entries(supportingFiles)) {
            // Skip mocks folder installation
            if (dirName === 'mocks') {
                continue;
            }
            for (const file of files) {
                // Supporting files already have their directory in the name (e.g., "constants/validationErrorMessages.ts")
                // So we install them directly under basePath
                let filePath = path_1.default.resolve(basePathDir, file.name);
                // If file exists and user chose not to overwrite, generate unique filename
                if (shouldCreateWithSuffix && await fs_extra_1.default.pathExists(filePath)) {
                    filePath = generateUniqueFilename(filePath);
                    console.log(chalk_1.default.blue(`📝 Creating supporting file with unique name: ${path_1.default.relative(cwd, filePath)}`));
                }
                // Create the file (either new or with unique name)
                if (!await fs_extra_1.default.pathExists(filePath)) {
                    await fs_extra_1.default.ensureDir(path_1.default.dirname(filePath));
                    // Transform imports to use existing project aliases
                    const transformedContent = (0, transformers_1.transformImports)(file.content, { ...resolvedConfig, projectAliases, basePath });
                    await fs_extra_1.default.writeFile(filePath, transformedContent);
                    console.log(chalk_1.default.green(`✓ Created: ${path_1.default.relative(cwd, filePath)}`));
                }
                else if (!shouldCreateWithSuffix) {
                    console.log(chalk_1.default.gray(`ℹ Already exists: ${path_1.default.relative(cwd, filePath)}`));
                }
            }
        }
        // Update aliases to include supporting file directories at basePath level
        // Use the first component name as a reference (aliases point to basePath level, not component level)
        if (componentsToInstall.length > 0) {
            await (0, aliasManager_1.createAliasesFromBasePath)(cwd, basePath, componentsToInstall[0].name);
        }
        spinner.text = 'Installing dependencies...';
        // Install npm dependencies
        if (allDependencies.size > 0) {
            await (0, dependencies_1.installDependencies)(Array.from(allDependencies), cwd, {
                addToPackageJson: true
            });
        }
        // Provide informative success message
        if (shouldCreateWithSuffix) {
            spinner.succeed('Components installed successfully with unique filenames!');
            console.log(chalk_1.default.blue('\n📋 Summary:'));
            console.log(chalk_1.default.green(`✓ Files installed (existing files preserved with (1), (2), etc. suffix)`));
        }
        else {
            spinner.succeed('Components installed successfully!');
        }
        console.log(chalk_1.default.blue('\n📦 Installed components:'));
        componentsToInstall.forEach(comp => {
            console.log(chalk_1.default.green(`  ✓ ${comp.name}`));
        });
        if (allDependencies.size > 0) {
            console.log(chalk_1.default.blue('\n📚 Dependencies installed:'));
            Array.from(allDependencies).forEach(dep => {
                console.log(chalk_1.default.green(`  ✓ ${dep}`));
            });
        }
        componentsToInstall.forEach(comp => {
        });
        if (allDependencies.size > 0) {
            Array.from(allDependencies).forEach(dep => {
            });
        }
    }
    catch (error) {
        spinner.fail('Failed to install components');
        console.error(chalk_1.default.red('Error:'), error);
        process.exit(1);
    }
}
//# sourceMappingURL=add.js.map