"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 });
const core_1 = require("@oclif/core");
const inquirer_1 = __importDefault(require("inquirer"));
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const crypto = __importStar(require("crypto"));
const chalk_1 = __importDefault(require("chalk"));
/**
 * TEACHING NOTE: This is an oclif Command class
 * - oclif automatically finds commands in src/commands/
 * - Each command extends Command base class
 * - Static properties define metadata (description, flags)
 * - run() method contains the actual logic
 */
class Init extends core_1.Command {
    // Command description shown in help
    static description = 'Initialize a new DataBridge project';
    // Command usage examples
    static examples = [
        '<%= config.bin %> <%= command.id %>',
        '<%= config.bin %> <%= command.id %> --skip-prompts',
    ];
    // Flags = optional parameters users can pass
    static flags = {
        'skip-prompts': core_1.Flags.boolean({
            description: 'Skip interactive prompts and use defaults',
            default: false,
        }),
    };
    /**
     * Main command logic - runs when user types "databridge init"
     */
    async run() {
        const { flags } = await this.parse(Init);
        // 1. Print welcome message
        this.log(chalk_1.default.bold.blue('\n🚀 DataBridge Project Initialization\n'));
        // 2. Ask user questions (or use defaults if --skip-prompts)
        const answers = await this.promptUser(flags['skip-prompts']);
        // 3. Create config file
        await this.createConfig(answers);
        // 4. Create package.json with required dependencies
        await this.createPackageJson();
        // 5. Initialize Prisma schema
        await this.initPrismaSchema(answers.databaseUrl);
        // 6. Copy bundled dependencies so Prisma is available for introspection
        await this.copyBundledDependencies();
        // 7. Print success message
        this.log(chalk_1.default.green('\n✅ DataBridge initialized successfully!\n'));
        this.log(chalk_1.default.bold('Next steps:'));
        this.log('  1. Run: ' + chalk_1.default.cyan('databridge introspect') + ' (introspect your database)');
        this.log('  2. Run: ' + chalk_1.default.cyan('databridge generate') + ' (generate API code)');
        this.log('  3. Run: ' + chalk_1.default.cyan('npm run dev') + ' (start API server)\n');
    }
    /**
     * TEACHING NOTE: inquirer is a library for interactive CLI prompts
     * It shows questions and collects answers from the user
     */
    async promptUser(skipPrompts) {
        if (skipPrompts) {
            // Use sensible defaults when skipping prompts
            return {
                databaseUrl: 'mysql://root:password@localhost:3306/testdb',
                apiOutputPath: 'apps/api/src',
                angularOutputPath: 'src/app/databridge',
                jwtSecret: this.generateSecret(),
            };
        }
        // Interactive prompts - inquirer will show these one by one
        return inquirer_1.default.prompt([
            {
                type: 'input',
                name: 'databaseUrl',
                message: 'MySQL database URL:',
                default: 'mysql://root:password@localhost:3306/testdb',
                validate: (input) => {
                    // Basic validation - must start with mysql://
                    if (!input.startsWith('mysql://')) {
                        return 'Database URL must start with mysql://';
                    }
                    return true;
                },
            },
            {
                type: 'input',
                name: 'apiOutputPath',
                message: 'API output path:',
                default: 'apps/api/src',
            },
            {
                type: 'input',
                name: 'angularOutputPath',
                message: 'Angular SDK output path:',
                default: 'src/app/databridge',
            },
            {
                type: 'confirm',
                name: 'generateJwt',
                message: 'Generate JWT secret for authentication?',
                default: true,
            },
        ]).then((answers) => ({
            ...answers,
            jwtSecret: answers.generateJwt ? this.generateSecret() : '',
        }));
    }
    /**
     * TEACHING NOTE: fs-extra is like fs (Node's file system) but with extra features
     * - ensureDir: Creates directory if it doesn't exist (no error if exists)
     * - writeJSON: Writes JavaScript object as formatted JSON file
     */
    async createConfig(answers) {
        const configPath = path.join(process.cwd(), '.databridge.json');
        // Check if config already exists
        if (await fs.pathExists(configPath)) {
            this.log(chalk_1.default.yellow('\n⚠️  .databridge.json already exists. Overwriting...\n'));
        }
        // Config object that will be saved
        const config = {
            version: '0.1.0',
            database: {
                url: answers.databaseUrl,
            },
            api: {
                outputPath: answers.apiOutputPath,
                port: 3000,
                cors: '*',
            },
            angular: {
                outputPath: answers.angularOutputPath,
            },
            auth: {
                jwtSecret: answers.jwtSecret,
            },
        };
        // Write config to file (spaces: 2 means pretty formatting with 2-space indent)
        await fs.writeJSON(configPath, config, { spaces: 2 });
        this.log(chalk_1.default.green(`✓ Created ${configPath}`));
    }
    /**
     * Create package.json with required dependencies
     * This ensures the project has all needed packages with correct versions
     */
    async createPackageJson() {
        const packagePath = path.join(process.cwd(), 'package.json');
        // Don't overwrite existing package.json
        if (await fs.pathExists(packagePath)) {
            this.log(chalk_1.default.yellow('✓ package.json already exists, skipping...'));
            return;
        }
        const packageJson = {
            name: 'databridge-project',
            version: '0.1.0',
            private: true,
            description: 'DataBridge generated project',
            scripts: {
                dev: 'tsx apps/api/src/index.ts',
                build: 'tsc',
                start: 'node apps/api/dist/index.js'
            },
            dependencies: {
                '@prisma/client': '5.22.0',
                '@prisma/engines': '5.22.0',
                'fastify': '5.6.2',
                '@fastify/cors': '11.1.0',
                'fastify-plugin': '5.1.0',
                'pino': '9.6.0',
                'pino-pretty': '13.1.2',
                'zod': '3.25.76'
            },
            devDependencies: {
                'prisma': '5.22.0',
                'tsx': '4.20.6',
                '@types/node': '^20.0.0',
                'typescript': '^5.0.0'
            }
        };
        await fs.writeJSON(packagePath, packageJson, { spaces: 2 });
        this.log(chalk_1.default.green(`✓ Created ${packagePath}`));
    }
    /**
     * TEACHING NOTE: This creates the initial Prisma schema file
     * Prisma is an ORM (Object-Relational Mapping) tool
     * schema.prisma defines your database structure
     */
    async initPrismaSchema(databaseUrl) {
        const schemaPath = path.join(process.cwd(), 'prisma', 'schema.prisma');
        // Don't overwrite if schema already exists
        if (await fs.pathExists(schemaPath)) {
            this.log(chalk_1.default.yellow('✓ Prisma schema already exists, skipping...'));
            return;
        }
        // Template for Prisma schema
        const schemaContent = `// DataBridge Prisma Schema
// Learn more: https://pris.ly/d/prisma-schema

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

// Your models will appear here after running "databridge introspect"
// Example:
// model Product {
//   id        Int      @id @default(autoincrement())
//   name      String
//   price     Float
//   createdAt DateTime @default(now())
// }
`;
        // Create prisma directory and write schema
        await fs.ensureDir(path.dirname(schemaPath));
        await fs.writeFile(schemaPath, schemaContent.trim());
        this.log(chalk_1.default.green(`✓ Created ${schemaPath}`));
        // Also create .env file with DATABASE_URL
        const envPath = path.join(process.cwd(), '.env');
        if (!(await fs.pathExists(envPath))) {
            await fs.writeFile(envPath, `DATABASE_URL="${databaseUrl}"\n`);
            this.log(chalk_1.default.green(`✓ Created ${envPath}`));
        }
    }
    /**
     * TEACHING NOTE: Generates a random secret for JWT tokens
     * - crypto is Node's built-in cryptography module
     * - randomBytes(32) generates 32 random bytes
     * - toString('hex') converts to hexadecimal string
     */
    generateSecret() {
        return crypto.randomBytes(32).toString('hex');
    }
    /**
     * Copy bundled dependencies from CLI package to project
     * This provides Prisma and other dependencies without npm install
     */
    async copyBundledDependencies() {
        this.log(chalk_1.default.gray('\n📦 Copying bundled dependencies...'));
        // Find CLI root (where bundled-deps lives)
        const cliRoot = path.join(__dirname, '..', '..');
        const bundleSource = path.join(cliRoot, 'bundled-deps', 'node_modules');
        const targetPath = path.join(process.cwd(), 'node_modules');
        if (!(await fs.pathExists(bundleSource))) {
            this.log(chalk_1.default.yellow('⚠️  No bundled dependencies found.'));
            this.log(chalk_1.default.yellow('   You\'ll need to run: npm install'));
            return;
        }
        this.log(chalk_1.default.gray('   This may take a moment...'));
        // Copy node_modules from bundle
        await fs.ensureDir(targetPath);
        await fs.copy(bundleSource, targetPath, {
            overwrite: true,
            dereference: true // Follow symlinks (important for Windows)
        });
        this.log(chalk_1.default.green('✓ Dependencies copied (Prisma 5.22.0 ready to use!)'));
    }
}
exports.default = Init;
//# sourceMappingURL=init.js.map