import { Args, Command, Flags } from '@oclif/core';
import { execFileSync } from 'node:child_process';
import { loadSchema } from '../../generator/domain/schema-loader.js';
import { loadLockFiles } from '../../generator/engine/lock-file.js';
import { generateBackModule } from '../../generator/handlers/back.handler.js';
import { generateFrontModule } from '../../generator/handlers/front.handler.js';
export default class Generate extends Command {
    static args = {
        scope: Args.string({
            description: 'Scope where the command will act.',
            options: ['back', 'front'],
            required: true,
        }),
        // eslint-disable-next-line perfectionist/sort-objects -- positional order matters for oclif
        element: Args.string({
            description: 'Type of element to generate.',
            options: ['module'],
            required: true,
        }),
    };
    static description = "Generate a module's source code from its YAML definition.";
    static examples = [
        '<%= config.bin %> generate back module --name=iam/account',
        '<%= config.bin %> generate front module --name=iam/account',
        '<%= config.bin %> generate back module --name=iam/account --tests --force',
        '<%= config.bin %> generate back module --name=iam/account --target=api',
    ];
    static flags = {
        force: Flags.boolean({
            char: 'f',
            default: false,
            description: 'Overwrite existing files.',
        }),
        name: Flags.string({
            char: 'n',
            description: 'Bounded context and module (e.g. "iam/account").',
            required: true,
        }),
        noGraphQLTypes: Flags.boolean({
            char: 'g',
            default: false,
            description: 'Skip GraphQL type generation.',
        }),
        overwriteInterface: Flags.boolean({
            char: 'w',
            default: false,
            description: 'Overwrite front-end interfaces.',
        }),
        target: Flags.string({
            description: 'Output subdirectory (default: "backend" for back, "frontend" for front).',
        }),
        tests: Flags.boolean({
            char: 't',
            default: false,
            description: 'Generate e2e test files.',
        }),
        verbose: Flags.boolean({
            char: 'v',
            default: false,
            description: 'Report all steps on screen.',
        }),
    };
    async run() {
        const { args, flags } = await this.parse(Generate);
        if (args.element !== 'module')
            return;
        const scope = args.scope;
        const defaultDir = scope === 'back' ? 'backend' : 'frontend';
        const baseDir = flags.target ?? defaultDir;
        const { boundedContextName, moduleName } = this.parseName(flags.name);
        const schema = loadSchema(boundedContextName, moduleName);
        const lockFiles = loadLockFiles(boundedContextName, moduleName, scope);
        const ctx = {
            baseDir,
            flags: {
                force: flags.force,
                noGraphQLTypes: flags.noGraphQLTypes,
                overwriteInterface: flags.overwriteInterface,
                tests: flags.tests,
                verbose: flags.verbose,
            },
            lockFiles,
            overwrittenFiles: [],
            schema,
            scope,
        };
        let originFiles = [];
        if (args.scope === 'back') {
            const result = await generateBackModule(ctx, {
                hasTestingFiles: flags.tests,
            });
            originFiles = result.originFiles;
            this.log(`Back-end module "${boundedContextName}/${moduleName}" generated.`);
            if (!flags.noGraphQLTypes) {
                this.log('Generating GraphQL types...');
                try {
                    execFileSync('pnpm', ['back:graphql:types'], { stdio: 'inherit' });
                }
                catch {
                    this.warn('GraphQL type generation failed. Run "pnpm back:graphql:types" manually.');
                }
            }
        }
        if (args.scope === 'front') {
            const result = await generateFrontModule(ctx);
            originFiles = result.originFiles;
            this.log(`Front-end module "${boundedContextName}/${moduleName}" generated.`);
        }
        if (originFiles.length > 0) {
            const count = originFiles.length;
            const noun = count === 1 ? 'file' : 'files';
            this.log(`${count} origin ${noun} pending review. Run "catalyst origin list" to inspect or "catalyst origin review" for an interactive walk-through.`);
        }
    }
    parseName(name) {
        const parts = name.split('/');
        if (parts.length !== 2 || !parts[0] || !parts[1]) {
            this.error('The --name flag must follow the format "bounded-context/module" (e.g. "iam/account").');
        }
        return {
            boundedContextName: parts[0],
            moduleName: parts[1],
        };
    }
}
