import select from '@inquirer/select';
import { Command, Flags } from '@oclif/core';
import jsYaml from 'js-yaml';
import { existsSync, readdirSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
import ora from 'ora';
import { loadConfig } from '../../deploy/domain/config.js';
import { initializeSheetsApi } from '../../sheets/domain/auth.js';
import { formatDiff, formatDiffSummary, } from '../../sheets/sync/diff-engine.js';
import { listModulesInSheet } from '../../sheets/sync/sheet-to-yaml.js';
export default class Diff extends Command {
    static description = 'Show differences between Aurora YAML schemas and Google Sheets.';
    static examples = [
        '<%= config.bin %> sheets diff --bc iam',
        '<%= config.bin %> sheets diff --all',
        '<%= config.bin %> sheets diff --all --summary',
    ];
    static flags = {
        all: Flags.boolean({
            description: 'Diff all bounded contexts',
            exclusive: ['bc'],
        }),
        bc: Flags.string({
            description: 'Bounded context name',
        }),
        config: Flags.string({
            char: 'c',
            default: './aurora.yaml',
            description: 'Path to aurora.yaml config file',
        }),
        summary: Flags.boolean({
            description: 'Show only summary',
        }),
    };
    async run() {
        const { flags } = await this.parse(Diff);
        const config = loadConfig(flags.config);
        if (!config.sheets) {
            this.error('No "sheets" section found in aurora.yaml.\n' +
                'Add a sheets.bounded_contexts block to your config.');
        }
        const allNames = Object.keys(config.sheets.boundedContexts);
        if (allNames.length === 0) {
            this.error('No bounded contexts configured in sheets section.');
        }
        let boundedContexts;
        if (flags.all) {
            boundedContexts = allNames;
        }
        else if (flags.bc) {
            if (!config.sheets.boundedContexts[flags.bc]) {
                this.error(`Bounded context "${flags.bc}" not found.\nAvailable: ${allNames.join(', ')}`);
            }
            boundedContexts = [flags.bc];
        }
        else {
            const selected = await select({
                choices: allNames.map((name) => ({
                    description: config.sheets.boundedContexts[name].description,
                    name,
                    value: name,
                })),
                message: 'Select a bounded context to diff:',
            });
            boundedContexts = [selected];
        }
        const spinner = ora();
        spinner.start('Authenticating with Google Sheets...');
        const sheetsApi = await initializeSheetsApi();
        spinner.succeed('Authenticated with Google Sheets');
        const allDiffs = [];
        for (const bc of boundedContexts) {
            spinner.start(`Comparing: ${bc}`);
            const bcConfig = config.sheets.boundedContexts[bc];
            // eslint-disable-next-line no-await-in-loop
            const diffs = await this.diffBoundedContext(sheetsApi, bcConfig.spreadsheetId, bc);
            allDiffs.push(...diffs);
            spinner.succeed(`Compared: ${bc}`);
            if (!flags.summary) {
                for (const diff of diffs) {
                    this.log(formatDiff(diff));
                }
            }
        }
        this.log(formatDiffSummary(allDiffs));
    }
    async diffBoundedContext(sheetsApi, spreadsheetId, boundedContextName) {
        const cliterPath = './cliter';
        const bcPath = join(cliterPath, boundedContextName);
        const diffs = [];
        // Load YAML schemas
        const yamlSchemas = new Map();
        if (existsSync(bcPath)) {
            const files = readdirSync(bcPath);
            for (const file of files) {
                if (!file.endsWith('.aurora.yaml'))
                    continue;
                const content = readFileSync(join(bcPath, file), 'utf8');
                const schema = jsYaml.load(content);
                yamlSchemas.set(schema.moduleName, schema);
            }
        }
        // Load Sheet modules
        const modules = await listModulesInSheet(sheetsApi, spreadsheetId);
        // Compare
        for (const [name] of yamlSchemas) {
            if (modules.includes(name)) {
                diffs.push({
                    hasChanges: false,
                    metadataChanges: {},
                    moduleName: name,
                    pivotsChanged: [],
                    propertiesAdded: [],
                    propertiesModified: [],
                    propertiesRemoved: [],
                });
            }
            else {
                diffs.push({
                    hasChanges: true,
                    metadataChanges: {},
                    moduleName: name,
                    pivotsChanged: [],
                    propertiesAdded: [],
                    propertiesModified: [],
                    propertiesRemoved: [],
                });
            }
        }
        // Modules only in Sheet
        for (const mod of modules) {
            if (!yamlSchemas.has(mod)) {
                diffs.push({
                    hasChanges: true,
                    metadataChanges: {
                        _note: { sheet: '(exists)', yaml: '(not found)' },
                    },
                    moduleName: mod,
                    pivotsChanged: [],
                    propertiesAdded: [],
                    propertiesModified: [],
                    propertiesRemoved: [],
                });
            }
        }
        return diffs;
    }
}
