import { BaseCommand } from '../BaseCommand.js';
import { D1SqlMigrations } from '../d1/D1SqlMigrations.js';
import { WranglerConfig } from '../d1/WranglerConfig.js';
import { WranglerD1 } from '../d1/WranglerD1.js';
import { resolveNpmPath } from '../../common/index.js';
import { appConfig } from '../../config/app.js';
import { databaseConfig } from '../../config/database.js';
import { Logger } from '../../config/logger.js';
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
import * as path from '../../node-singletons/path.js';
const RESOLVED_VOID = Promise.resolve();
const runWrangler = async (cmd, args) => {
    // Back-compat entrypoint for tests; we only use this for D1 migrations apply.
    const dbName = args[3];
    const mode = args[4];
    const isLocal = mode === '--local';
    await RESOLVED_VOID;
    return WranglerD1.applyMigrations({ cmd, dbName, isLocal });
};
const getDbName = (projectRoot, options) => {
    const value = options['database'];
    if (typeof value === 'string' && value.trim() !== '')
        return value.trim();
    const resolution = WranglerConfig.resolveD1Database(projectRoot);
    if (resolution.status === 'resolved') {
        return WranglerConfig.getDefaultD1DatabaseName(projectRoot) ?? 'zintrust_db';
    }
    if (resolution.status === 'ambiguous') {
        throw ErrorFactory.createCliError('Multiple D1 targets are configured. Re-run with --database <database_name|binding> to choose the intended Wrangler D1 target.');
    }
    return 'zintrust_db';
};
const buildExecutionContext = (options) => {
    const isWorkerCommand = process.argv.includes('d1:migrate:worker');
    const isLocal = options['local'] === true || options['remote'] !== true;
    const projectRoot = process.cwd();
    const dbName = getDbName(projectRoot, options);
    const migrationsRelDir = isWorkerCommand
        ? path.join('database', 'migrations', 'd1')
        : WranglerConfig.getD1MigrationsDir(projectRoot, dbName);
    const sourceMigrationsDir = isWorkerCommand
        ? path.join('packages', 'workers', 'migrations')
        : databaseConfig.migrations.directory;
    return {
        isLocal,
        dbName,
        projectRoot,
        migrationsRelDir,
        sourceMigrationsDir,
        outputDir: path.join(projectRoot, migrationsRelDir),
    };
};
const handleMigrationError = (cmd, error) => {
    Logger.error('D1 Migration failed', error);
    ErrorFactory.createCliError('D1 Migration failed', error);
    const err = error;
    if (err.stdout !== undefined && err.stdout.length > 0)
        cmd.info(err.stdout.toString());
    if (err.stderr !== undefined && err.stderr.length > 0) {
        const stderr = err.stderr.toString();
        Logger.error('Wrangler stderr', stderr);
        ErrorFactory.createCliError('Wrangler stderr', stderr);
    }
    throw error;
};
const executeD1Migrate = async (cmd, options) => {
    const ctx = buildExecutionContext(options);
    cmd.info(`Running D1 migrations for ${ctx.dbName} (${ctx.isLocal ? 'local' : 'remote'})...`);
    cmd.info(`Generating D1 SQL migrations into ${ctx.migrationsRelDir}...`);
    await RESOLVED_VOID;
    try {
        const generated = await D1SqlMigrations.compileAndWrite({
            projectRoot: ctx.projectRoot,
            globalDir: ctx.sourceMigrationsDir,
            extension: databaseConfig.migrations.extension,
            includeGlobal: true,
            outputDir: ctx.outputDir,
        });
        cmd.info(`Generated ${generated.length} SQL migration file(s).`);
        const output = WranglerD1.applyMigrations({ cmd, dbName: ctx.dbName, isLocal: ctx.isLocal });
        if (output !== '')
            cmd.info(output);
        cmd.info('✓ D1 migrations completed successfully');
    }
    catch (error) {
        handleMigrationError(cmd, error);
    }
};
/**
 * D1 Migrate Command
 * Run Cloudflare D1 migrations using Wrangler
 */
/**
 * D1 Migrate Command Factory
 */
export const D1MigrateCommand = Object.freeze({
    /**
     * Create a new D1 migrate command instance
     */
    create() {
        const addOptions = (command) => {
            command
                .option('--local', 'Run against local D1 database (via wrangler dev)')
                .option('--remote', 'Run against remote D1 database (production)')
                .option('--database <name>', 'Wrangler D1 identifier. Accepts database_name or binding; defaults to the configured wrangler d1_databases entry when available.');
        };
        const cmd = BaseCommand.create({
            name: 'd1:migrate',
            description: 'Run Cloudflare D1 migrations',
            aliases: ['d1:migrate:worker'],
            addOptions,
            execute: async (options) => executeD1Migrate(cmd, options),
        });
        cmd.resolveNpmPath = () => resolveNpmPath();
        cmd.getSafeEnv = () => appConfig.getSafeEnv();
        cmd.runWrangler = async (args) => runWrangler(cmd, args);
        return cmd;
    },
});
