/**
 * Review Command - Code review with AI
 */
import chalk from 'chalk';
import { Marked } from 'marked';
import { markedTerminal } from 'marked-terminal';
import { createSpinner, CH } from '../utils/logger.js';
import { APIClient, CLIError, classifyError, formatCLIError } from '../utils/api.js';
import { FileUtils } from '../utils/files.js';
export class ReviewCommand {
    config;
    logger;
    api;
    fileUtils;
    marked;
    constructor(config, logger) {
        this.config = config;
        this.logger = logger;
        this.api = new APIClient(config, logger);
        this.fileUtils = new FileUtils(process.cwd(), config.get('project').ignorePatterns);
        this.marked = new Marked();
        this.marked.use(markedTerminal({
            showSectionPrefix: false,
            tab: 2,
            width: 80,
            reflowText: true,
        }));
    }
    async run(filePath, options) {
        // Check auth
        if (!this.config.isAuthenticated()) {
            this.logger.error('Not authenticated. Run: vigthoria login');
            return;
        }
        // Server-side token validation — fail fast instead of waiting for 401
        const tokenCheck = await this.api.validateToken();
        if (!tokenCheck.valid) {
            this.logger.error(tokenCheck.error || 'Auth token is invalid. Run: vigthoria login');
            return;
        }
        // Read file
        const file = this.fileUtils.readFile(filePath);
        if (!file) {
            this.logger.error(`File not found: ${filePath}`);
            return;
        }
        this.logger.section(`Reviewing: ${file.relativePath}`);
        console.log(chalk.gray(`Language: ${file.language} | Lines: ${file.lines}`));
        console.log();
        const spinner = createSpinner({
            text: 'Analyzing code quality...',
            spinner: 'dots',
        }).start();
        try {
            const review = await this.api.reviewCode(file.content, file.language);
            spinner.stop();
            // Format output
            switch (options.format) {
                case 'json':
                    console.log(JSON.stringify(review, null, 2));
                    break;
                case 'markdown':
                    this.printMarkdownReview(review, file.relativePath);
                    break;
                case 'text':
                default:
                    this.printTextReview(review);
                    break;
            }
        }
        catch (error) {
            spinner.stop();
            const cliErr = error instanceof CLIError ? error : classifyError(error);
            this.logger.error(formatCLIError(cliErr));
        }
    }
    printTextReview(review) {
        // Score
        const scoreColor = review.score >= 80 ? chalk.green : review.score >= 60 ? chalk.yellow : chalk.red;
        console.log();
        console.log(chalk.bold('Quality Score: ') + scoreColor(`${review.score}/100`));
        console.log(this.renderScoreBar(review.score));
        console.log();
        // Issues
        if (review.issues.length > 0) {
            this.logger.section(`Issues (${review.issues.length})`);
            review.issues.forEach((issue, i) => {
                const severityIcon = this.getSeverityIcon(issue.severity);
                const severityColor = this.getSeverityColor(issue.severity);
                console.log(severityColor(`${severityIcon} [${issue.type}]`) +
                    chalk.gray(` Line ${issue.line}:`) +
                    ` ${issue.message}`);
            });
            console.log();
        }
        else {
            this.logger.success('No issues found!');
        }
        // Suggestions
        if (review.suggestions.length > 0) {
            this.logger.section('Suggestions');
            review.suggestions.forEach((suggestion, i) => {
                console.log(chalk.cyan(`${i + 1}.`) + ` ${suggestion}`);
            });
            console.log();
        }
    }
    printMarkdownReview(review, filePath) {
        let markdown = `# Code Review: ${filePath}\n\n`;
        markdown += `## Score: ${review.score}/100\n\n`;
        if (review.issues.length > 0) {
            markdown += `## Issues\n\n`;
            review.issues.forEach(issue => {
                markdown += `- **[${issue.severity.toUpperCase()}]** Line ${issue.line}: ${issue.message} (${issue.type})\n`;
            });
            markdown += '\n';
        }
        if (review.suggestions.length > 0) {
            markdown += `## Suggestions\n\n`;
            review.suggestions.forEach((s, i) => {
                markdown += `${i + 1}. ${s}\n`;
            });
        }
        console.log(this.cleanTerminalOutput(this.marked.parse(markdown)));
    }
    renderScoreBar(score) {
        const width = 30;
        const filled = Math.round((score / 100) * width);
        const empty = width - filled;
        const color = score >= 80 ? chalk.green : score >= 60 ? chalk.yellow : chalk.red;
        const filledChar = process.platform === 'win32' ? '#' : '\u2588';
        const emptyChar = process.platform === 'win32' ? '.' : '\u2591';
        return color(filledChar.repeat(filled)) + chalk.gray(emptyChar.repeat(empty));
    }
    /**
     * Clean marked-terminal output for release-grade CLI presentation.
     */
    cleanTerminalOutput(raw) {
        let out = raw;
        out = out.replace(/^  \* /gm, '- ');
        out = out.replace(/^    \* /gm, '  - ');
        const stripAnsi = (s) => s.replace(/\x1b\[[0-9;]*m/g, '');
        out = out.split('\n').filter(line => {
            if (line === '')
                return true;
            return stripAnsi(line).trim().length > 0;
        }).join('\n');
        out = out.replace(/\n{3,}/g, '\n\n');
        return out;
    }
    getSeverityIcon(severity) {
        switch (severity.toLowerCase()) {
            case 'error':
                return CH.error;
            case 'warning':
                return CH.warn;
            case 'info':
                return CH.info;
            default:
                return CH.bullet;
        }
    }
    getSeverityColor(severity) {
        switch (severity.toLowerCase()) {
            case 'error':
                return chalk.red;
            case 'warning':
                return chalk.yellow;
            case 'info':
                return chalk.blue;
            default:
                return chalk.white;
        }
    }
}
