"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@oclif/core");
const path = __importStar(require("node:path"));
const fs = __importStar(require("node:fs"));
const spec_1 = require("@flui-cloud/spec");
const chalk_1 = __importDefault(require("chalk"));
class CatalogValidate extends core_1.Command {
    async run() {
        const { argv } = await this.parse(CatalogValidate);
        const files = argv;
        const results = files.map((f) => this.validateFile(path.resolve(f)));
        for (const r of results)
            this.printResult(r);
        const okCount = results.filter((r) => r.ok).length;
        const failCount = results.length - okCount;
        const validLabel = chalk_1.default.bold(`${okCount}/${results.length} valid`);
        const failLabel = chalk_1.default.red(`${failCount} failed`);
        const failSuffix = failCount > 0 ? `, ${failLabel}` : '';
        const summary = `\n${validLabel}${failSuffix}`;
        this.log(failCount > 0 ? chalk_1.default.red(summary) : chalk_1.default.green(summary));
        if (failCount > 0)
            this.exit(1);
    }
    validateFile(filePath) {
        let raw;
        try {
            raw = fs.readFileSync(filePath, 'utf-8');
        }
        catch (err) {
            return {
                path: filePath,
                ok: false,
                errors: [
                    `cannot read file: ${err instanceof Error ? err.message : String(err)}`,
                ],
            };
        }
        let parsed;
        try {
            parsed = (0, spec_1.parseYaml)(raw);
        }
        catch (err) {
            const msg = err instanceof Error ? err.message : String(err);
            return { path: filePath, ok: false, errors: [`invalid YAML: ${msg}`] };
        }
        const result = (0, spec_1.validate)(parsed);
        if (!result.valid) {
            return {
                path: filePath,
                ok: false,
                errors: this.formatErrors(result.errors),
            };
        }
        return {
            path: filePath,
            ok: true,
            errors: [],
            ...this.summarize(result.manifest),
        };
    }
    summarize(manifest) {
        if (manifest.kind === 'CatalogApp') {
            return {
                kind: 'CatalogApp',
                slug: manifest.metadata.id,
                version: manifest.metadata.version,
                appType: manifest.spec.type,
                checksum: (0, spec_1.computeChecksum)(manifest),
            };
        }
        return {
            kind: 'Application',
            slug: manifest.metadata.name,
            version: manifest.apiVersion,
            appType: manifest.build?.strategy,
            checksum: (0, spec_1.computeChecksum)(manifest),
        };
    }
    formatErrors(errors) {
        return errors.map((e) => {
            const params = e.params ? ' ' + JSON.stringify(e.params) : '';
            return `${e.path} ${e.message}${params}`;
        });
    }
    printResult(result) {
        const rel = result.path.startsWith(process.cwd() + '/')
            ? result.path.slice(process.cwd().length + 1)
            : result.path;
        if (result.ok) {
            const tag = chalk_1.default.cyan(`[${result.kind}]`);
            const checksum = result.checksum?.slice(0, 12);
            this.log(`${chalk_1.default.green('✔')} ${tag} ${chalk_1.default.bold(rel)} ${chalk_1.default.dim(`(${result.slug}@${result.version}` +
                (result.appType ? `, type=${result.appType}` : '') +
                (checksum ? `, checksum=${checksum}…` : '') +
                ')')}`);
        }
        else {
            this.log(`${chalk_1.default.red('✘')} ${chalk_1.default.bold(rel)}`);
            for (const err of result.errors) {
                this.log(`  ${chalk_1.default.red('→')} ${err}`);
            }
        }
    }
}
CatalogValidate.description = 'Validate one or more flui.yaml manifests against the flui spec. ' +
    'Supports both `kind: CatalogApp` (full schema) and `kind: Application` (lightweight checks).';
CatalogValidate.examples = [
    '<%= config.bin %> <%= command.id %> ./flui.yaml',
    '<%= config.bin %> <%= command.id %> ./catalog/vaultwarden.flui.yaml ./catalog/memos.flui.yaml',
];
CatalogValidate.strict = false;
CatalogValidate.args = {
    file: core_1.Args.string({
        description: 'Path to a flui.yaml file (repeatable)',
        required: true,
    }),
};
exports.default = CatalogValidate;
