"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 });
exports.TidyCommand = void 0;
const chalk_1 = __importDefault(require("chalk"));
const ora_1 = __importDefault(require("ora"));
const inquirer_1 = __importDefault(require("inquirer"));
const TidyService_1 = require("../services/TidyService");
const SubAgentOrchestrator_1 = require("../agents/orchestrator/SubAgentOrchestrator");
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const SKELETON_TYPE_LABELS = {
    "missing-skeleton": "Page skeleton",
    "stale-skeleton": "Stale skeleton",
    "missing-loading": "loading.tsx",
    "missing-error": "error.tsx",
    "missing-not-found": "not-found.tsx",
};
class TidyCommand {
    register(program) {
        program
            .command("tidy [directory]")
            .description("🧹 Clean up hardcoded values and standardize with design tokens")
            .option("--tokens", "Standardize CSS design tokens (hex colors → CSS variables)", true)
            .option("--constants", "Standardize hardcoded strings with constants", true)
            .option("--semantic-tailwind", "Map default Tailwind palette classes to semantic theme utilities (shadcn/globals)", true)
            .option("--dark-contrast", "Normalize risky text/background contrast with dark-safe Tailwind variants", true)
            .option("--skeletons", "Generate/update page skeletons and routing pages", true)
            .option("--dry-run", "Show suggestions without applying changes")
            .option("--interactive", "Confirm each replacement interactively", true)
            .option("--fix", "Automatically apply all high-confidence suggestions")
            .option("--exclude <patterns...>", "Exclude files/patterns from scanning (e.g., globals.css tailwind.config)")
            .option("--no-cleanup", "Skip automatic cleanup of circular/duplicate tokens")
            .action(async (directory, options) => {
            await this.run(directory || ".", options);
        });
    }
    async run(directory, options) {
        // Parse exclude patterns from options
        const excludePatterns = options.exclude || [];
        const tidyService = new TidyService_1.TidyService(directory, excludePatterns);
        await tidyService.initialize();
        // 0. Auto-Clean design toxins (only if not disabled)
        if (options.cleanup !== false) {
            const removed = await tidyService.cleanupCircularTokens();
            if (removed > 0) {
                console.log(chalk_1.default.green(`✨ Cleaned up ${removed} circular reference tokens in CSS.`));
            }
        }
        // 1. Audit tokens & constants
        const spinner = (0, ora_1.default)("🤖 Scanning project for hardcoded literals...").start();
        try {
            spinner.text = "Auditing codebase for hardcoded literals...";
            const auditOpts = {
                hexTokens: options.tokens !== false,
                constants: options.constants !== false,
                semanticTailwind: options.semanticTailwind !== false,
                darkContrast: options.darkContrast !== false,
            };
            const suggestions = await tidyService.audit(["src", "app", "components", "lib"], auditOpts);
            spinner.stop();
            if (suggestions.length === 0) {
                console.log(chalk_1.default.green("\n✨ No hardcoded literals found. Your project is already tidy!\n"));
            }
            else {
                console.log(chalk_1.default.blue(`\n🔍 Found ${suggestions.length} hardcoded literals:\n`));
                if (options.dryRun) {
                    this.displaySuggestions(suggestions);
                }
                else if (options.fix && !options.interactive) {
                    console.log(chalk_1.default.yellow("Auto-fix not yet implemented. Use interactive mode."));
                }
                else if (options.interactive) {
                    await this.runInteractive(suggestions, tidyService, directory);
                }
            }
            // 2. Audit skeletons & routing pages
            if (options.skeletons !== false) {
                await this.runSkeletonAudit(tidyService, options);
            }
        }
        catch (error) {
            spinner.fail(`Tidy failed: ${error.message}`);
            process.exit(1);
        }
    }
    async runSkeletonAudit(service, options) {
        const spinner = (0, ora_1.default)("🦴 Scanning for missing skeletons and routing pages...").start();
        try {
            const skeletonSuggestions = await service.auditSkeletons();
            spinner.stop();
            if (skeletonSuggestions.length === 0) {
                console.log(chalk_1.default.green("\n✨ All pages have proper skeletons and routing files!\n"));
                return;
            }
            console.log(chalk_1.default.blue(`\n🦴 Found ${skeletonSuggestions.length} skeleton/routing issues:\n`));
            for (const s of skeletonSuggestions) {
                const label = SKELETON_TYPE_LABELS[s.type] || s.type;
                console.log(`  ${chalk_1.default.yellow("⚠")} ${chalk_1.default.cyan(`[${label}]`)} ` +
                    `${chalk_1.default.dim(s.pagePath)} → ${chalk_1.default.green(s.targetFile)}`);
            }
            console.log();
            if (options.dryRun)
                return;
            if (options.fix) {
                let applied = 0;
                for (const s of skeletonSuggestions) {
                    const ok = await service.applySkeleton(s);
                    if (ok)
                        applied++;
                }
                console.log(chalk_1.default.green(`✅ Generated ${applied} skeleton/routing files.\n`));
                return;
            }
            if (options.interactive) {
                await this.runSkeletonInteractive(skeletonSuggestions, service);
            }
        }
        catch (error) {
            spinner.fail(`Skeleton audit failed: ${error.message}`);
        }
    }
    async runSkeletonInteractive(suggestions, service) {
        let applied = 0;
        for (const s of suggestions) {
            const label = SKELETON_TYPE_LABELS[s.type] || s.type;
            const { approve } = await inquirer_1.default.prompt([{
                    type: "confirm",
                    name: "approve",
                    message: `Generate ${chalk_1.default.cyan(label)} for ${chalk_1.default.dim(s.pagePath)} → ${chalk_1.default.green(s.targetFile)}?`,
                    default: true,
                }]);
            if (approve) {
                const ok = await service.applySkeleton(s);
                if (ok) {
                    console.log(chalk_1.default.green(`  ✅ Created ${s.targetFile}`));
                    applied++;
                }
                else {
                    console.log(chalk_1.default.red(`  ❌ Failed to create ${s.targetFile}`));
                }
            }
        }
        console.log(chalk_1.default.blue(`\nDone. Generated ${applied} skeleton/routing files.\n`));
    }
    displaySuggestions(suggestions) {
        for (const s of suggestions) {
            const location = chalk_1.default.gray(`${s.file}:${s.line}`);
            const change = `${chalk_1.default.red(s.original)} → ${chalk_1.default.green(s.replacement)}`;
            const type = chalk_1.default.cyan(`[${s.type}]`);
            const amb = s.ambiguousCandidates && s.ambiguousCandidates.length > 1
                ? chalk_1.default.dim(` [or: ${s.ambiguousCandidates.join(", ")}]`)
                : "";
            const pair = s.pairedWith && s.rationale
                ? chalk_1.default.dim(`\n    ${s.pairedWith}: ${s.rationale}`)
                : s.rationale
                    ? chalk_1.default.dim(`\n    ${s.rationale}`)
                    : "";
            const action = s.action ? chalk_1.default.dim(` [${s.action}]`) : "";
            console.log(`${location} ${type}${action} ${change}${amb} (conf: ${Math.round(s.confidence * 100)}%)${pair}`);
        }
    }
    async runInteractive(suggestions, service, rootDir) {
        let appliedCount = 0;
        const total = suggestions.length;
        for (let i = 0; i < suggestions.length; i++) {
            const s = suggestions[i];
            if (!s)
                continue; // TypeScript guard
            let replacement = s.replacement;
            let tokenName = s.tokenName;
            // Show progress
            console.log(chalk_1.default.dim(`\n[${i + 1}/${total}]`));
            // If it's a new token, ask the AI for a suggested name
            if (s.type === "new_token") {
                const spinner = (0, ora_1.default)(`AI is suggesting a name for ${chalk_1.default.red(s.original)}...`).start();
                try {
                    const absPath = path.join(rootDir, s.file);
                    const content = await fs.readFile(absPath, "utf-8");
                    const lines = content.split("\n");
                    const lineContext = lines.slice(Math.max(0, s.line - 3), Math.min(lines.length, s.line + 2)).join("\n");
                    const aiResult = await SubAgentOrchestrator_1.orchestrator.executeAgent("TidyAgent", {
                        literal: s.original,
                        contextCode: lineContext,
                        type: "color"
                    });
                    spinner.stop();
                    tokenName = aiResult.suggestedName;
                    replacement = `var(--${tokenName})`;
                    s.tokenName = tokenName; // Update suggestion object for application logic
                }
                catch (e) {
                    spinner.fail("AI naming failed. Falling back to generic label.");
                    tokenName = "BRAND_TOKEN";
                    replacement = `var(--${tokenName})`;
                    s.tokenName = tokenName;
                }
            }
            if (s.type === "tailwind_semantic" &&
                s.ambiguousCandidates &&
                s.ambiguousCandidates.length > 1) {
                const spinner = (0, ora_1.default)(`AI choosing semantic class for ${chalk_1.default.red(s.original)}...`).start();
                try {
                    const absPath = path.join(rootDir, s.file);
                    const content = await fs.readFile(absPath, "utf-8");
                    const lines = content.split("\n");
                    const lineContext = lines.slice(Math.max(0, s.line - 3), Math.min(lines.length, s.line + 2)).join("\n");
                    const aiResult = await SubAgentOrchestrator_1.orchestrator.executeAgent("TidyAgent", {
                        literal: s.original,
                        contextCode: lineContext,
                        type: "tailwind_class",
                        allowedReplacements: s.ambiguousCandidates,
                    });
                    spinner.stop();
                    replacement = aiResult.suggestedName;
                    s.replacement = replacement;
                }
                catch (e) {
                    spinner.fail("AI selection failed. Using first candidate.");
                    replacement = s.ambiguousCandidates[0] ?? s.replacement;
                    s.replacement = replacement;
                }
            }
            const contrastNote = s.rationale && s.pairedWith
                ? ` (${s.pairedWith}: ${s.rationale})`
                : s.rationale
                    ? ` (${s.rationale})`
                    : "";
            const actionNote = s.action ? ` [${s.action}]` : "";
            const { approve } = await inquirer_1.default.prompt([
                {
                    type: "confirm",
                    name: "approve",
                    message: `Replace ${chalk_1.default.red(s.original)} with ${chalk_1.default.green(replacement)} in ${chalk_1.default.cyan(s.file + ":" + s.line)}?${actionNote}${contrastNote}`,
                    default: true
                }
            ]);
            if (approve) {
                // If it's a new token, we first need to append it to the token file
                if (s.type === "new_token" && tokenName) {
                    await service.appendNewToken(tokenName, s.original, "token");
                }
                const success = await service.applySuggestion(s);
                if (success) {
                    console.log(chalk_1.default.green(`✅ Applied in ${s.file}`));
                    appliedCount++;
                }
                else {
                    console.log(chalk_1.default.red(`❌ Failed to apply in ${s.file}`));
                }
            }
        }
        console.log(chalk_1.default.blue(`\nDone. Applied ${appliedCount}/${total} refactors.`));
    }
}
exports.TidyCommand = TidyCommand;
//# sourceMappingURL=tidy.js.map