"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 fastify_1 = __importDefault(require("fastify"));
const cors_1 = __importDefault(require("@fastify/cors"));
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const glob_1 = require("glob");
const chalk_1 = __importDefault(require("chalk"));
/**
 * TEACHING NOTE: This command starts a web server!
 *
 * What is Fastify?
 * - A web framework (like Express, but faster)
 * - Handles HTTP requests (GET /products, POST /products, etc.)
 * - Returns responses (JSON data)
 *
 * What is CORS?
 * - Cross-Origin Resource Sharing
 * - Allows your Angular app (http://localhost:4200) to talk to API (http://localhost:3000)
 * - Without CORS, browsers block these requests for security
 */
class Serve extends core_1.Command {
    static description = 'Start the DataBridge API server';
    static examples = [
        '<%= config.bin %> <%= command.id %>',
        '<%= config.bin %> <%= command.id %> --port 4000',
    ];
    static flags = {
        port: core_1.Flags.integer({
            char: 'p',
            description: 'Port to run server on',
        }),
        host: core_1.Flags.string({
            char: 'h',
            description: 'Host to bind to',
            default: '0.0.0.0',
        }),
    };
    async run() {
        const { flags } = await this.parse(Serve);
        this.log(chalk_1.default.bold.blue('\n🚀 Starting DataBridge API server...\n'));
        // 1. Load config
        const config = await this.loadConfig();
        const port = flags.port || config.api.port || 3000;
        const host = flags.host;
        // 2. Create Fastify instance
        const fastify = (0, fastify_1.default)({
            logger: {
                // Pretty logging for development
                transport: {
                    target: 'pino-pretty',
                    options: {
                        translateTime: 'HH:MM:ss',
                        ignore: 'pid,hostname',
                    },
                },
            },
        });
        // 3. Register plugins
        await this.registerPlugins(fastify, config);
        // 4. Register all generated routes
        await this.registerRoutes(fastify, config);
        // 5. Health check endpoint
        fastify.get('/health', async () => {
            return { status: 'ok', timestamp: new Date().toISOString() };
        });
        // 6. Start server
        try {
            await fastify.listen({ port, host });
            this.log(chalk_1.default.green('✅ Server started successfully!\n'));
            this.log(chalk_1.default.bold('Server details:'));
            this.log(chalk_1.default.gray(`  URL:     http://localhost:${port}`));
            this.log(chalk_1.default.gray(`  Health:  http://localhost:${port}/health`));
            this.log(chalk_1.default.gray(`  CORS:    ${config.api.cors || 'Enabled for all origins'}`));
            this.log(chalk_1.default.bold('\nAvailable routes:'));
            // Show all registered routes
            const routes = fastify.printRoutes();
            this.log(chalk_1.default.gray(routes));
            this.log(chalk_1.default.yellow('\nPress Ctrl+C to stop\n'));
            // Keep process running
            await new Promise(() => { });
        }
        catch (err) {
            this.error(chalk_1.default.red(`Failed to start server: ${err.message}`));
        }
    }
    async loadConfig() {
        const configPath = path.join(process.cwd(), '.databridge.json');
        if (!(await fs.pathExists(configPath))) {
            this.error('No .databridge.json found. Run "databridge init" first.');
        }
        return fs.readJSON(configPath);
    }
    /**
     * TEACHING NOTE: Register plugins
     * Plugins add functionality to Fastify
     * - CORS: Allow cross-origin requests
     * - Prisma: Database connection (we'll create this)
     */
    async registerPlugins(fastify, config) {
        // CORS - Allow Angular app to call this API
        await fastify.register(cors_1.default, {
            origin: config.api.cors || '*', // * means allow all origins
            credentials: true,
        });
        this.log(chalk_1.default.green('✓ CORS enabled'));
        // Try to load Prisma plugin if it exists
        const prismaPluginPath = path.join(process.cwd(), config.api.outputPath, 'plugins', 'prisma.ts');
        if (await fs.pathExists(prismaPluginPath)) {
            try {
                // Dynamic import of the Prisma plugin
                // Convert to file:// URL for Windows compatibility
                const pluginUrl = process.platform === 'win32'
                    ? `file:///${prismaPluginPath.replace(/\\/g, '/')}`
                    : prismaPluginPath;
                const { default: prismaPlugin } = await Promise.resolve(`${pluginUrl}`).then(s => __importStar(require(s)));
                await fastify.register(prismaPlugin);
                this.log(chalk_1.default.green('✓ Prisma plugin loaded'));
            }
            catch (error) {
                this.log(chalk_1.default.yellow(`⚠️  Could not load Prisma plugin: ${error.message}`));
                this.log(chalk_1.default.gray('    The API will start but database operations will fail'));
            }
        }
        else {
            this.log(chalk_1.default.yellow('⚠️  No Prisma plugin found. Creating one...'));
            await this.createPrismaPlugin(config);
            this.log(chalk_1.default.green('✓ Prisma plugin created. Restart server to use it.'));
        }
    }
    /**
     * TEACHING NOTE: Auto-register all generated routes
     *
     * This finds all .ts files in the routes/ folder
     * and registers them with Fastify
     *
     * Each file exports a function like:
     * export default async function productRoutes(fastify) { ... }
     */
    async registerRoutes(fastify, config) {
        const routesDir = path.join(process.cwd(), config.api.outputPath, 'routes');
        if (!(await fs.pathExists(routesDir))) {
            this.log(chalk_1.default.yellow('\n⚠️  No routes found. Run "databridge generate" first.\n'));
            return;
        }
        // Find all TypeScript files in routes directory
        const routeFiles = await (0, glob_1.glob)('**/*.{ts,js}', {
            cwd: routesDir,
            absolute: true,
            ignore: ['**/_*.{ts,js}', '**/*.d.ts'], // Ignore private files and type definitions
        });
        if (routeFiles.length === 0) {
            this.log(chalk_1.default.yellow('⚠️  No route files found in routes directory'));
            return;
        }
        this.log(chalk_1.default.bold(`\n📂 Loading ${routeFiles.length} route file(s):`));
        for (const file of routeFiles) {
            const routeName = path.basename(file, path.extname(file));
            try {
                // Dynamic import of route file
                // Convert to file:// URL for Windows compatibility
                const fileUrl = process.platform === 'win32'
                    ? `file:///${file.replace(/\\/g, '/')}`
                    : file;
                const routeModule = await Promise.resolve(`${fileUrl}`).then(s => __importStar(require(s)));
                const routeHandler = routeModule.default;
                if (typeof routeHandler === 'function') {
                    await fastify.register(routeHandler);
                    this.log(chalk_1.default.gray(`  ✓ /${routeName}`));
                }
                else {
                    this.log(chalk_1.default.yellow(`  ✗ ${routeName} (no default export)`));
                }
            }
            catch (error) {
                this.log(chalk_1.default.red(`  ✗ ${routeName} failed: ${error.message}`));
            }
        }
    }
    /**
     * TEACHING NOTE: Create Prisma plugin
     * This creates a simple plugin that:
     * 1. Creates Prisma client instance
     * 2. Makes it available globally as "prisma"
     * 3. Handles cleanup on server shutdown
     */
    async createPrismaPlugin(config) {
        const pluginDir = path.join(process.cwd(), config.api.outputPath, 'plugins');
        const pluginPath = path.join(pluginDir, 'prisma.ts');
        await fs.ensureDir(pluginDir);
        const pluginContent = `import { FastifyInstance } from 'fastify';
import { PrismaClient } from '@prisma/client';
import fastifyPlugin from 'fastify-plugin';

/**
 * Prisma plugin for Fastify
 * Makes Prisma client available globally
 */
export const prisma = new PrismaClient();

async function prismaPlugin(fastify: FastifyInstance) {
  // Make prisma available in routes
  fastify.decorate('prisma', prisma);

  // Cleanup on server close
  fastify.addHook('onClose', async () => {
    await prisma.$disconnect();
  });
}

export default fastifyPlugin(prismaPlugin);
`;
        await fs.writeFile(pluginPath, pluginContent);
    }
}
exports.default = Serve;
//# sourceMappingURL=serve.js.map