'use strict';

/**
 * Contract: schema validate
 *
 * Validate schema files: single-model (implicit via defineModel) + cross-model.
 * Mendukung positional <path> (default ./schema).
 *
 * Inline migration v4.0.0: business logic dari dbschema-validate.js
 * dipindah ke handler. Per Phase 3 decision (Phase 2 #2): flag legacy yang
 * tidak ter-expose di contract (--format, --dialect, --strict, --strict-warnings)
 * tidak di-promote. Inline minimal pakai default human format + strict=false.
 */

const path = require('path');

const { loadSchemaPath } = require('../../lib/dbschema-kit/loader');
const { validateCrossModel } = require('../../lib/dbschema-kit/validator/cross-model-validator');
const { validateTypeCompatibility } = require('../../lib/dbschema-kit/validator/type-compatibility-validator');
const { validateCircularRelations } = require('../../lib/dbschema-kit/validator/circular-relation-validator');
const { validateCheckCompatibility } = require('../../lib/dbschema-kit/validator/check-compatibility-validator');
const { reportHuman, getExitCode } = require('../../lib/dbschema-kit/validator/validator-reporter');
const { defineModel } = require('../../lib/dbschema-kit/define-model');

function listSchemaFiles(absPath) {
    const fs = require('fs');
    const stat = fs.statSync(absPath);
    if (stat.isFile()) {
        return path.extname(absPath) === '.js' ? [absPath] : [];
    }
    const entries = fs.readdirSync(absPath).sort();
    const files = [];
    for (const entry of entries) {
        const entryPath = path.join(absPath, entry);
        if (!fs.statSync(entryPath).isFile()) continue;
        if (path.extname(entry) !== '.js') continue;
        files.push(entryPath);
    }
    return files;
}

function printSuccessLines(absPath, models) {
    const files = listSchemaFiles(absPath);
    for (const filePath of files) {
        const cached = require.cache[filePath];
        const factory = cached ? cached.exports : null;
        if (typeof factory !== 'function') continue;
        let ir;
        try {
            ir = factory({ defineModel });
        } catch (_) {
            continue;
        }
        if (ir && typeof ir.tableName === 'string') {
            const qualified = ir.qualifiedName || ir.tableName;
            if (models.has(qualified)) {
                console.log(`✓ ${filePath}: ${qualified}`);
            }
        }
    }
}

module.exports = {
    resource: 'schema',
    verb: 'validate',
    description: 'Memvalidasi file schema definition (single-model dan cross-model)',
    category: 'introspection',
    flags: {
        path: {
            type: 'string',
            required: true,
            description: 'Path file atau folder schema (mis. ./schema atau ./schema/users.js)'
        }
    },
    examples: [
        'npx restforge schema validate --path=./schema',
        'npx restforge schema validate --path=./my-schema'
    ],
    async handler(args) {
        const schemaPath = args.path;
        const absPath = path.resolve(process.cwd(), schemaPath);

        let models;
        try {
            models = loadSchemaPath(absPath);
        } catch (err) {
            console.error(`✗ ${err.message}`);
            console.error('');
            console.error('0 models loaded, 1 error.');
            throw err;
        }

        const crossModelIssues = validateCrossModel(models);
        const typeCompatIssues = validateTypeCompatibility(models);
        const circularIssues = validateCircularRelations(models);
        const checkCompatIssues = validateCheckCompatibility(models);

        const allIssues = [
            ...crossModelIssues,
            ...typeCompatIssues,
            ...circularIssues,
            ...checkCompatIssues
        ];

        const filteredIssues = allIssues.filter((i) => i.severity === 'error');

        printSuccessLines(absPath, models);
        reportHuman(filteredIssues, models.size);

        const exitCode = getExitCode(filteredIssues, false);
        if (exitCode !== 0) {
            const err = new Error(`schema validate detected ${filteredIssues.length} error(s)`);
            err.exitCode = exitCode;
            throw err;
        }
    }
};
