'use strict';

/**
 * Contract: processor list
 *
 * Menampilkan daftar processor dari workbench metadata di working directory
 * (`metadata/<project>-workbench.json` map `processors`, output dari
 * `processor create`). File backup (`.backup.` / `.corrupt.`) di-skip.
 *
 * Kolom:
 * - Processor Name : key di `workbench.processors`
 * - Payload        : nama file `payload/<processor>.json` bila ada, `-` bila tidak
 * - Processor      : daftar function berformat `nama (METHOD)`; di-wrap
 *                    maksimal 4 function per baris, tanpa pemotongan
 *
 * Output default berupa table human-readable (`--format=text`). Output JSON
 * (untuk konsumsi AI agent / mcp-server) tersedia via `--format=json`.
 */

const fs = require('fs');
const path = require('path');
const ConfigReader = require('../../lib/config/config-reader');

/**
 * Baca semua entry processor dari file workbench metadata di working directory.
 * Read-only: file yang corrupt di-skip dengan warning, tidak ditulis ulang.
 *
 * @param {string} workingDir
 * @returns {{ project: string, name: string, payload: string|null, processor: { name: string, method: string }[] }[]}
 */
function readProcessorEntries(workingDir) {
    const metadataDir = path.join(workingDir, 'metadata');
    if (!fs.existsSync(metadataDir)) {
        return [];
    }

    const files = fs.readdirSync(metadataDir).filter(name =>
        name.endsWith('-workbench.json') &&
        !name.includes('.backup.') &&
        !name.includes('.corrupt.')
    );

    const entries = [];

    for (const file of files) {
        let metadata;
        try {
            metadata = JSON.parse(fs.readFileSync(path.join(metadataDir, file), 'utf8'));
        } catch (error) {
            console.warn(`Warning: skipping unreadable metadata file: ${file} (${error.message})`);
            continue;
        }

        if (!metadata || typeof metadata.processors !== 'object' || metadata.processors === null) {
            continue;
        }

        const project = metadata.projectName || path.basename(file, '-workbench.json');

        for (const [processorName, processorData] of Object.entries(metadata.processors)) {
            const payloadFile = `${processorName}.json`;
            const hasPayload = fs.existsSync(path.join(workingDir, 'payload', payloadFile));

            const procs = processorData && Array.isArray(processorData.processor)
                ? processorData.processor.map(proc => ({
                    name: proc.name,
                    method: proc.method
                }))
                : [];

            entries.push({
                project,
                name: processorName,
                payload: hasPayload ? payloadFile : null,
                processor: procs
            });
        }
    }

    entries.sort((a, b) => a.name.localeCompare(b.name));
    return entries;
}

/**
 * Konversi pattern glob sederhana (`*` = karakter apa pun) menjadi RegExp
 * case-insensitive yang match keseluruhan nama. Tanpa wildcard berarti
 * exact match.
 * @param {string} pattern
 * @returns {RegExp}
 */
function patternToRegExp(pattern) {
    const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
    return new RegExp('^' + escaped.replace(/\*/g, '.*') + '$', 'i');
}

/**
 * Potong string dengan suffix '..' bila melebihi lebar kolom (pola `project list`).
 * @param {string} value
 * @param {number} width
 * @returns {string}
 */
function truncate(value, width) {
    return value.length > width - 2
        ? value.substring(0, width - 4) + '..'
        : value;
}

/**
 * Render daftar processor ke format table human-readable.
 * @param {{ name: string, payload: string|null, processor: { name: string, method: string }[] }[]} entries
 * @returns {string}
 */
function renderHumanTable(entries) {
    const lines = [];

    const colName = 24;
    const colPayload = 28;
    const colProcessor = 44;

    lines.push('');
    lines.push('Registered Processors:');
    lines.push('');
    lines.push(
        'Processor Name'.padEnd(colName) +
        'Payload'.padEnd(colPayload) +
        'Processor'.padEnd(colProcessor)
    );
    lines.push('-'.repeat(colName + colPayload + colProcessor));

    const PROCS_PER_LINE = 4;

    for (const entry of entries) {
        // Wrap function per 4 item; baris pertama menyatu dengan kolom lain,
        // baris lanjutan di-indent sejajar kolom Processor.
        const labels = entry.processor.map(proc =>
            proc.method ? `${proc.name} (${proc.method})` : proc.name
        );

        const procLines = [];
        if (labels.length === 0) {
            procLines.push('-');
        } else {
            for (let i = 0; i < labels.length; i += PROCS_PER_LINE) {
                const chunk = labels.slice(i, i + PROCS_PER_LINE).join(', ');
                const isLast = i + PROCS_PER_LINE >= labels.length;
                procLines.push(isLast ? chunk : chunk + ',');
            }
        }

        lines.push(
            truncate(entry.name, colName).padEnd(colName) +
            truncate(entry.payload || '-', colPayload).padEnd(colPayload) +
            procLines[0]
        );
        for (const continuation of procLines.slice(1)) {
            lines.push(' '.repeat(colName + colPayload) + continuation);
        }
    }

    lines.push('');
    lines.push(`Total: ${entries.length} processor(s)`);
    lines.push('');

    return lines.join('\n');
}

module.exports = {
    resource: 'processor',
    verb: 'list',
    description: 'Menampilkan daftar processor dari workbench metadata di working directory',
    category: 'management',
    flags: {
        format: {
            type: 'string',
            required: false,
            default: 'text',
            description: 'Format output: `text` (table human-readable) atau `json` (untuk AI agent / mcp-server)'
        },
        name: {
            type: 'string',
            required: false,
            default: null,
            description: 'Filter nama processor, case-insensitive. Wildcard `*` = karakter apa pun (mis. `*order*`); tanpa wildcard berarti exact match'
        }
    },
    examples: [
        'npx restforge processor list',
        'npx restforge processor list --format=json',
        'npx restforge processor list --name=*order*'
    ],
    async handler(args) {
        const workingDir = ConfigReader.getWorkingDirectory();
        const allEntries = readProcessorEntries(workingDir);
        const format = (args.format || 'text').toLowerCase();

        const entries = args.name
            ? allEntries.filter(e => patternToRegExp(args.name).test(e.name))
            : allEntries;

        if (format === 'json') {
            const summary = {
                totalProcessors: entries.length,
                projects: [...new Set(entries.map(e => e.project))].sort()
            };
            if (args.name) {
                summary.namePattern = args.name;
            }
            const output = {
                schemaVersion: '1.0',
                source: 'processor-list',
                summary,
                processors: entries
            };
            process.stdout.write(JSON.stringify(output, null, 2) + '\n');
            return;
        }

        if (allEntries.length === 0) {
            console.log('');
            console.log('No processors found in this project.');
            console.log('');
            console.log('Use "npx restforge processor create" to create a new processor.');
            console.log('');
            return;
        }

        process.stdout.write(renderHumanTable(entries) + '\n');
    }
};
