'use strict';

/**
 * Contract: schema list
 *
 * Live database schema discovery: list semua tabel (dan view) dari database
 * yang ter-konfigurasi di file .env. Agnostic terhadap PostgreSQL, MySQL, dan
 * Oracle.
 *
 * Output default berupa table human-readable yang di-group per schema. Output
 * JSON (untuk konsumsi AI agent / mcp-server) tersedia via `--format=json`.
 *
 * Inline migration v4.0.0: business logic dari dbschema-list.js
 * dipindah ke handler. parseArguments/showHelp/process.exit dihilangkan
 * (handled oleh validateContract + cli-entry.js).
 */

const { DatabaseIntrospector } = require('../../lib/utils/database-introspector');
const { resolveConfig, printDefaultConfigWarning } = require('../../lib/utils/config-resolver');

/**
 * Render daftar tabel ke format table human-readable, di-group per schema.
 * @param {{schema:string,name:string,type:string}[]} tables
 * @param {string[]} schemas
 * @param {string} dbType
 */
function renderHumanTable(tables, schemas, dbType) {
    const lines = [];

    if (tables.length === 0) {
        lines.push('');
        lines.push(`No tables found (database: ${dbType}).`);
        lines.push('');
        return lines.join('\n');
    }

    const COL_NAME = 36;
    const COL_TYPE = 8;

    for (const schema of schemas) {
        const inSchema = tables.filter(t => t.schema === schema);
        if (inSchema.length === 0) continue;

        lines.push('');
        lines.push(`schema: ${schema}`);
        lines.push('');
        lines.push('Object Name'.padEnd(COL_NAME) + '| Type');
        lines.push('-'.repeat(COL_NAME) + '+' + '-'.repeat(COL_TYPE));

        for (const t of inSchema) {
            const name = t.name.length > COL_NAME - 1
                ? t.name.substring(0, COL_NAME - 3) + '..'
                : t.name;
            lines.push(name.padEnd(COL_NAME) + '| ' + t.type);
        }
    }

    const schemaWord = schemas.length === 1 ? 'schema' : 'schemas';
    const tableWord = tables.length === 1 ? 'table' : 'tables';
    lines.push('');
    lines.push(`Total: ${tables.length} ${tableWord} in ${schemas.length} ${schemaWord} (database: ${dbType})`);
    lines.push('');

    return lines.join('\n');
}

module.exports = {
    resource: 'schema',
    verb: 'list',
    description: 'Menampilkan daftar tabel pada database secara live introspection',
    category: 'introspection',
    flags: {
        config: {
            type: 'string',
            required: false,
            default: null,
            description: 'File config database (.env). Fallback ke `.restforge/defaults.json` bila tidak disediakan eksplisit (set via `config set-default`)'
        },
        schema: {
            type: 'string',
            required: false,
            default: null,
            description: 'Filter berdasarkan nama schema (default: semua non-system)'
        },
        'include-system': {
            type: 'boolean',
            required: false,
            default: false,
            description: 'Sertakan system schemas'
        },
        format: {
            type: 'string',
            required: false,
            default: 'table',
            description: 'Format output: `table` (human-readable, di-group per schema) atau `json` (untuk AI agent / mcp-server)'
        },
        pretty: {
            type: 'boolean',
            required: false,
            default: true,
            description: 'Pretty-print output JSON (hanya berlaku saat --format=json)'
        }
    },
    examples: [
        'npx restforge schema list --config=db.env',
        'npx restforge schema list --config=db.env --schema=public',
        'npx restforge schema list --config=db.env --format=json'
    ],
    async handler(args) {
        const resolved = resolveConfig(args.config, process.cwd());
        if (!resolved) {
            console.error("Error: --config=<file.env> is required");
            console.error("Tip: set a default with 'npx restforge config set-default --config=<file>' to omit --config in future runs");
            console.error("Run 'npx restforge schema list --help' for usage information");
            throw new Error('--config=<file.env> is required');
        }

        if (resolved.source === 'default') {
            printDefaultConfigWarning(resolved.defaultName);
        }

        const introspector = new DatabaseIntrospector({ quiet: true });
        const configPath = resolved.path;

        if (!introspector.loadConfig(configPath)) {
            throw new Error(`Failed to load config: ${configPath}`);
        }

        const connected = await introspector.connect();
        if (!connected) {
            throw new Error('Failed to connect to database');
        }

        try {
            const tables = await introspector.listTables({
                schemaFilter: args.schema,
                includeSystem: args['include-system']
            });

            const schemas = [...new Set(tables.map(t => t.schema))].sort();

            const tablesOut = tables.map(t => ({
                schema: t.schema,
                name: t.name,
                type: t.type
            }));

            const format = (args.format || 'table').toLowerCase();

            if (format === 'json') {
                const output = {
                    schemaVersion: '1.0',
                    source: 'dbschema-list',
                    summary: {
                        totalTables: tablesOut.length,
                        schemas,
                        database: introspector.dbType
                    },
                    tables: tablesOut
                };

                const json = args.pretty
                    ? JSON.stringify(output, null, 2)
                    : JSON.stringify(output);
                process.stdout.write(json + '\n');
            } else {
                process.stdout.write(
                    renderHumanTable(tablesOut, schemas, introspector.dbType) + '\n'
                );
            }
        } catch (error) {
            console.error(`Error: ${error.message}`);
            if (process.env.DEBUG) {
                console.error(error.stack);
            }
            throw error;
        } finally {
            await introspector.disconnect();
        }
    }
};
