'use strict';

/**
 * Contract: schema describe
 *
 * Live database schema discovery: describe satu tabel — columns, primary key,
 * foreign keys, indexes. Agnostic terhadap PostgreSQL, MySQL, dan Oracle.
 *
 * Inline migration v4.0.0: business logic dari dbschema-describe.js
 * dipindah ke handler.
 */

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

function buildColumns(detailedColumns, pkColumns) {
    const pkSet = new Set(pkColumns.map(c => c.toLowerCase()));

    return detailedColumns.map(col => {
        const charLen = col.character_maximum_length;
        const numPrec = col.numeric_precision;
        const numScale = col.numeric_scale;
        const baseType = col.data_type;

        let displayType = baseType;
        if (charLen) {
            displayType = `${baseType}(${charLen})`;
        } else if (numPrec && numScale !== null && numScale !== undefined && numScale !== 0) {
            displayType = `${baseType}(${numPrec},${numScale})`;
        } else if (numPrec && (numScale === 0 || numScale === null || numScale === undefined)) {
            if (baseType === 'numeric' || baseType === 'decimal') {
                displayType = `${baseType}(${numPrec})`;
            }
        }

        return {
            name: col.column_name,
            type: displayType,
            nullable: col.is_nullable === 'YES' || col.is_nullable === true || col.is_nullable === 1,
            primaryKey: pkSet.has((col.column_name || '').toLowerCase()),
            default: col.column_default !== undefined ? col.column_default : null
        };
    });
}

module.exports = {
    resource: 'schema',
    verb: 'describe',
    description: 'Menampilkan detail struktur satu tabel: kolom, primary key, foreign keys, indexes',
    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`)'
        },
        table: {
            type: 'string',
            required: true,
            description: 'Nama tabel (unqualified atau qualified public.users)'
        },
        'include-foreign-keys': {
            type: 'boolean',
            required: false,
            default: true,
            description: 'Sertakan informasi foreign key'
        },
        'include-indexes': {
            type: 'boolean',
            required: false,
            default: true,
            description: 'Sertakan informasi indexes'
        },
        pretty: {
            type: 'boolean',
            required: false,
            default: true,
            description: 'Pretty-print output JSON'
        }
    },
    examples: [
        'npx restforge schema describe --config=db.env --table=users',
        'npx restforge schema describe --config=db.env --table=public.orders --include-indexes=false'
    ],
    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 describe --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 { schema, table } = introspector.parseTableName(args.table);

            const [detailedColumns, constraints] = await Promise.all([
                introspector.getDetailedColumnInfo(args.table),
                introspector.getConstraints(args.table)
            ]);

            if (!detailedColumns || detailedColumns.length === 0) {
                throw new Error(`Table '${args.table}' not found or has no columns`);
            }

            const pkConstraint = constraints.find(c => c.type === 'PRIMARY KEY') || null;
            const pkColumns = pkConstraint ? pkConstraint.columns : [];
            const primaryKey = pkConstraint
                ? { name: pkConstraint.name, columns: pkConstraint.columns }
                : null;

            const columns = buildColumns(detailedColumns, pkColumns);

            const output = {
                schemaVersion: '1.0',
                source: 'dbschema-describe',
                table: {
                    schema,
                    name: table,
                    type: 'table'
                },
                columns,
                primaryKey,
                database: introspector.dbType
            };

            if (args['include-foreign-keys']) {
                output.foreignKeys = await introspector.getForeignKeys(args.table);
            }

            if (args['include-indexes']) {
                output.indexes = await introspector.getIndexes(args.table);
            }

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