import { execSync } from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import { PrismaClient } from '@prisma/client';
import { get4RunrDataDir } from '@4runr/shared';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
import { ensure4RunrStackRunning, waitForHealthy, getDockerStatus } from './docker-manager.js';
export async function initializeDatabase(logger) {
    const warnings = [];
    const persistenceMode = process.env['GATEWAY_PERSISTENCE'] || 'auto';
    if (persistenceMode === 'memory') {
        logger.info('GATEWAY_PERSISTENCE=memory - skipping database initialization');
        return { mode: 'memory', client: null };
    }
    if (process.env['DATABASE_URL'] && persistenceMode === 'postgres') {
        logger.info('Using explicitly configured DATABASE_URL');
        return await initializeWithExistingDatabase(logger);
    }
    logger.info('Checking Docker availability for local database...');
    const dockerStatus = await getDockerStatus();
    if (!dockerStatus.available) {
        logger.warn('⚠️  Docker not available. Falling back to memory-only mode.');
        warnings.push('Docker not installed - install Docker Desktop to enable persistent storage');
        return { mode: 'memory', client: null, warnings };
    }
    if (!dockerStatus.running) {
        logger.warn('⚠️  Docker daemon not running. Falling back to memory-only mode.');
        warnings.push('Docker is installed but not running - start Docker Desktop to enable persistent storage');
        return { mode: 'memory', client: null, warnings };
    }
    try {
        logger.info('Ensuring 4Runr Docker containers (Postgres + Redis) are running...');
        await startDockerContainers(logger);
        logger.info('Waiting for database to be ready...');
        await waitForHealthy('4runr-postgres', 60000);
        await waitForHealthy('4runr-redis', 15000);
        logger.info('✓ Database containers healthy');
        const databaseUrl = 'postgresql://4runr:4runr_dev_pass@localhost:5432/4runr_local';
        const redisUrl = 'redis://localhost:6379';
        process.env['DATABASE_URL'] = databaseUrl;
        process.env['REDIS_URL'] = redisUrl;
        logger.info('Running database migrations...');
        await runMigrations(databaseUrl, logger);
        logger.info('✓ Migrations complete');
        const client = new PrismaClient({
            datasources: {
                db: {
                    url: databaseUrl
                }
            },
            log: [
                { level: 'warn', emit: 'event' },
                { level: 'error', emit: 'event' }
            ]
        });
        client.$on('warn', (e) => logger.warn({ prisma: true }, e.message));
        client.$on('error', (e) => logger.error({ prisma: true }, e.message));
        await client.$connect();
        logger.info('✓ Database connection established');
        return {
            mode: 'docker',
            client,
            databaseUrl
        };
    }
    catch (err) {
        const errorMsg = err instanceof Error ? err.message : String(err);
        logger.error({ err }, 'Failed to initialize Docker database');
        logger.warn('⚠️  Falling back to memory-only mode');
        return {
            mode: 'memory',
            client: null,
            error: errorMsg,
            warnings: ['Database initialization failed - running in memory-only mode', errorMsg]
        };
    }
}
async function initializeWithExistingDatabase(logger) {
    try {
        const databaseUrl = process.env['DATABASE_URL'];
        logger.info('Running database migrations...');
        await runMigrations(databaseUrl, logger);
        logger.info('✓ Migrations complete');
        const client = new PrismaClient({
            log: [
                { level: 'warn', emit: 'event' },
                { level: 'error', emit: 'event' }
            ]
        });
        client.$on('warn', (e) => logger.warn({ prisma: true }, e.message));
        client.$on('error', (e) => logger.error({ prisma: true }, e.message));
        await client.$connect();
        logger.info('✓ Database connection established');
        return {
            mode: 'docker',
            client,
            databaseUrl
        };
    }
    catch (err) {
        const errorMsg = err instanceof Error ? err.message : String(err);
        logger.error({ err }, 'Failed to connect to database');
        return {
            mode: 'memory',
            client: null,
            error: errorMsg,
            warnings: ['Database connection failed - running in memory-only mode', errorMsg]
        };
    }
}
async function startDockerContainers(logger) {
    const dataDir = get4RunrDataDir();
    const composeFilePath = path.join(dataDir, 'docker-compose.yml');
    const possiblePaths = [
        path.join(process.cwd(), 'docker-compose.local.yml'),
        path.join(__dirname, '../../docker-compose.local.yml'),
        path.join(__dirname, '../../../docker-compose.local.yml'),
        path.join(__dirname, '../../../../docker-compose.local.yml'),
        path.join(process.cwd(), 'apps/gateway/docker-compose.local.yml'),
    ];
    let templatePath = null;
    for (const tryPath of possiblePaths) {
        if (fs.existsSync(tryPath)) {
            templatePath = tryPath;
            break;
        }
    }
    if (templatePath) {
        logger.info(`Syncing Docker Compose template from ${templatePath} → ${composeFilePath}`);
        fs.copyFileSync(templatePath, composeFilePath);
    }
    else if (!fs.existsSync(composeFilePath)) {
        throw new Error(`Docker Compose template not found. Tried: ${possiblePaths.join(', ')}`);
    }
    else {
        logger.warn(`Docker Compose template missing; using existing ${composeFilePath}`);
    }
    await ensure4RunrStackRunning(composeFilePath);
}
async function runMigrations(databaseUrl, logger) {
    const candidates = [
        path.join(process.cwd(), '..', '..', 'prisma', 'schema.prisma'),
        path.join(__dirname, '../../../../../prisma/schema.prisma'),
        path.join(__dirname, '../../../../prisma/schema.prisma'),
        path.join(__dirname, '../../../prisma/schema.prisma'),
        path.join(process.cwd(), 'prisma', 'schema.prisma'),
    ];
    let actualSchemaPath = null;
    for (const p of candidates) {
        if (fs.existsSync(p)) {
            actualSchemaPath = p;
            break;
        }
    }
    if (!actualSchemaPath) {
        logger.warn(`⚠️  Prisma schema not found (tried ${candidates.length} locations relative to Gateway), skipping migrations`);
        return;
    }
    try {
        const isLocalDocker = databaseUrl.includes('localhost:5432');
        const command = isLocalDocker
            ? `npx prisma db push --skip-generate --accept-data-loss`
            : `npx prisma migrate deploy`;
        execSync(command, {
            env: {
                ...process.env,
                DATABASE_URL: databaseUrl
            },
            cwd: path.dirname(actualSchemaPath),
            stdio: 'pipe',
            timeout: 60000
        });
    }
    catch (err) {
        const errorMsg = err instanceof Error ? err.message : String(err);
        logger.error(`Migration failed: ${errorMsg}`);
        throw new Error(`Database migration failed: ${errorMsg}`);
    }
}
export async function shutdownDatabase(client, logger) {
    if (client) {
        try {
            await client.$disconnect();
            logger.info('✓ Database connection closed');
        }
        catch (err) {
            logger.error({ err }, 'Error disconnecting from database');
        }
    }
    try {
        const { stop4RunrContainers } = await import('./docker-manager.js');
        await stop4RunrContainers();
        logger.info('✓ Docker containers stopped (data preserved)');
    }
    catch (err) {
        logger.debug('Could not stop Docker containers (may not be running)');
    }
}
//# sourceMappingURL=init.js.map