/**
 * Web Server Service
 *
 * Manages the Next.js programmatic server lifecycle.
 * Starts the web UI in the same Node.js process as the CLI,
 * sharing the DI container and application layer.
 *
 * Supports both development (dev: true) and production (dev: false) modes.
 * In production mode, Next.js serves the pre-built .next output.
 */
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { injectable } from 'tsyringe';
import next from 'next';
import http from 'node:http';
import path from 'node:path';
import fs from 'node:fs';
const defaultDeps = {
    createNextApp: next,
    createHttpServer: http.createServer,
};
/**
 * Resolve the web UI directory path.
 * Works in both development (src/) and production (dist/) contexts.
 *
 * Development: import.meta.dirname = <root>/src/infrastructure/services/
 *   → ../../presentation/web → <root>/src/presentation/web/
 *
 * Production (npm install): import.meta.dirname = <root>/dist/src/infrastructure/services/
 *   → ../../../../web → <root>/web/
 */
export function resolveWebDir() {
    // Check for development source directory first
    const devDir = path.resolve(import.meta.dirname, '../../presentation/web');
    if (fs.existsSync(path.join(devDir, 'next.config.ts'))) {
        return { dir: devDir, dev: true };
    }
    // Production: web UI is shipped alongside dist/ in the package
    // From dist/src/infrastructure/services/ we need 4 levels up to reach the package root
    const prodDir = path.resolve(import.meta.dirname, '../../../../web');
    if (fs.existsSync(path.join(prodDir, '.next'))) {
        return { dir: prodDir, dev: false };
    }
    throw new Error(`Web UI directory not found. Ensure the web UI is built (pnpm build:web).\n` +
        `  Searched:\n` +
        `    dev:  ${devDir} (next.config.ts: ${fs.existsSync(path.join(devDir, 'next.config.ts'))})\n` +
        `    prod: ${prodDir} (.next: ${fs.existsSync(path.join(prodDir, '.next'))})\n` +
        `  import.meta.dirname: ${import.meta.dirname}`);
}
let WebServerService = class WebServerService {
    app = null;
    server = null;
    isShuttingDown = false;
    deps;
    constructor(deps = {}) {
        this.deps = { ...defaultDeps, ...deps };
    }
    /**
     * Start the Next.js web server.
     * @param port - Port to listen on
     * @param dir - Path to the Next.js web package directory
     * @param dev - Whether to run in development mode (default: auto-detect)
     */
    async start(port, dir, dev = true) {
        const app = this.deps.createNextApp({
            dev,
            dir,
            port,
            hostname: 'localhost',
        });
        const handle = app.getRequestHandler();
        await app.prepare();
        this.app = app;
        await new Promise((resolve, reject) => {
            const server = this.deps.createHttpServer((req, res) => {
                handle(req, res);
            });
            server.on('error', reject);
            server.listen(port, 'localhost', () => {
                this.server = server;
                resolve();
            });
        });
    }
    /**
     * Gracefully stop the server.
     */
    async stop() {
        if (this.isShuttingDown)
            return;
        this.isShuttingDown = true;
        try {
            if (this.server) {
                await new Promise((resolve) => {
                    this.server.close(() => resolve());
                });
                this.server = null;
            }
            if (this.app) {
                await this.app.close();
                this.app = null;
            }
        }
        finally {
            this.isShuttingDown = false;
        }
    }
};
WebServerService = __decorate([
    injectable(),
    __metadata("design:paramtypes", [Object])
], WebServerService);
export { WebServerService };
