/**
 * File utilities for Vigthoria CLI
 */
import * as fs from 'fs';
import * as path from 'path';
import { glob } from 'glob';
export class FileUtils {
    projectRoot;
    ignorePatterns;
    constructor(projectRoot, ignorePatterns = []) {
        // Resolve symlinks and normalize path for consistent behavior
        try {
            this.projectRoot = fs.realpathSync(projectRoot);
        }
        catch {
            // If realpath fails (e.g., path doesn't exist), use the original
            this.projectRoot = path.resolve(projectRoot);
        }
        this.ignorePatterns = ignorePatterns;
    }
    // Read file with metadata
    readFile(filePath) {
        try {
            let absolutePath = path.isAbsolute(filePath)
                ? filePath
                : path.join(this.projectRoot, filePath);
            // Resolve symlinks for consistent path handling
            try {
                absolutePath = fs.realpathSync(absolutePath);
            }
            catch {
                // Keep original path if realpath fails
            }
            // Check if it's a regular file (not a directory or special file)
            const stats = fs.statSync(absolutePath);
            if (!stats.isFile()) {
                return null;
            }
            const content = fs.readFileSync(absolutePath, 'utf-8');
            const relativePath = path.relative(this.projectRoot, absolutePath);
            return {
                path: absolutePath,
                relativePath,
                content,
                language: this.detectLanguage(absolutePath),
                lines: content.split('\n').length,
            };
        }
        catch (error) {
            return null;
        }
    }
    // Read specific lines
    readLines(filePath, start, end) {
        const file = this.readFile(filePath);
        if (!file)
            return null;
        const lines = file.content.split('\n');
        return lines.slice(start - 1, end).join('\n');
    }
    // Write file
    writeFile(filePath, content) {
        try {
            const absolutePath = path.isAbsolute(filePath)
                ? filePath
                : path.join(this.projectRoot, filePath);
            // Create directory if needed
            const dir = path.dirname(absolutePath);
            if (!fs.existsSync(dir)) {
                fs.mkdirSync(dir, { recursive: true });
            }
            fs.writeFileSync(absolutePath, content, 'utf-8');
            return true;
        }
        catch {
            return false;
        }
    }
    // Backup file
    backupFile(filePath) {
        const file = this.readFile(filePath);
        if (!file)
            return null;
        const backupPath = `${file.path}.bak.${Date.now()}`;
        if (this.writeFile(backupPath, file.content)) {
            return backupPath;
        }
        return null;
    }
    // List project files
    async listFiles(pattern = '**/*') {
        try {
            // Check if project root exists
            if (!fs.existsSync(this.projectRoot)) {
                return [];
            }
            const files = await glob(pattern, {
                cwd: this.projectRoot,
                ignore: this.ignorePatterns,
                nodir: true,
            });
            return files;
        }
        catch (error) {
            // Return empty array on error (e.g., permission issues on Windows)
            return [];
        }
    }
    // Detect language from file extension
    detectLanguage(filePath) {
        const ext = path.extname(filePath).toLowerCase();
        const languageMap = {
            '.ts': 'typescript',
            '.tsx': 'typescript',
            '.js': 'javascript',
            '.jsx': 'javascript',
            '.py': 'python',
            '.rs': 'rust',
            '.go': 'go',
            '.java': 'java',
            '.c': 'c',
            '.cpp': 'cpp',
            '.h': 'c',
            '.hpp': 'cpp',
            '.cs': 'csharp',
            '.rb': 'ruby',
            '.php': 'php',
            '.swift': 'swift',
            '.kt': 'kotlin',
            '.scala': 'scala',
            '.sql': 'sql',
            '.html': 'html',
            '.css': 'css',
            '.scss': 'scss',
            '.less': 'less',
            '.json': 'json',
            '.yaml': 'yaml',
            '.yml': 'yaml',
            '.xml': 'xml',
            '.md': 'markdown',
            '.sh': 'bash',
            '.bash': 'bash',
            '.zsh': 'zsh',
            '.dockerfile': 'dockerfile',
            '.vue': 'vue',
            '.svelte': 'svelte',
        };
        return languageMap[ext] || 'text';
    }
    // Get project context
    async getProjectContext(maxFiles = 20) {
        const context = {
            type: 'unknown',
            files: [],
            dependencies: {},
        };
        // Detect project type
        if (fs.existsSync(path.join(this.projectRoot, 'package.json'))) {
            context.type = 'node';
            const pkg = JSON.parse(fs.readFileSync(path.join(this.projectRoot, 'package.json'), 'utf-8'));
            context.dependencies = {
                ...pkg.dependencies,
                ...pkg.devDependencies,
            };
        }
        else if (fs.existsSync(path.join(this.projectRoot, 'requirements.txt'))) {
            context.type = 'python';
        }
        else if (fs.existsSync(path.join(this.projectRoot, 'Cargo.toml'))) {
            context.type = 'rust';
        }
        else if (fs.existsSync(path.join(this.projectRoot, 'go.mod'))) {
            context.type = 'go';
        }
        else if (fs.existsSync(path.join(this.projectRoot, 'pom.xml'))) {
            context.type = 'java-maven';
        }
        else if (fs.existsSync(path.join(this.projectRoot, 'build.gradle'))) {
            context.type = 'java-gradle';
        }
        else if (fs.existsSync(path.join(this.projectRoot, 'core', 'core.services.yml')) ||
            fs.existsSync(path.join(this.projectRoot, 'web', 'core', 'core.services.yml')) ||
            fs.existsSync(path.join(this.projectRoot, 'sites', 'default', 'settings.php'))) {
            // Drupal 8/9/10/11 detection
            context.type = 'drupal';
            // Try to read composer.json for Drupal version info
            const composerPath = fs.existsSync(path.join(this.projectRoot, 'composer.json'))
                ? path.join(this.projectRoot, 'composer.json')
                : fs.existsSync(path.join(this.projectRoot, 'web', 'composer.json'))
                    ? path.join(this.projectRoot, 'web', 'composer.json')
                    : null;
            if (composerPath) {
                try {
                    const composer = JSON.parse(fs.readFileSync(composerPath, 'utf-8'));
                    context.dependencies = composer.require || {};
                }
                catch { /* ignore parse errors */ }
            }
        }
        else if (fs.existsSync(path.join(this.projectRoot, 'wp-config.php'))) {
            context.type = 'wordpress';
        }
        else if (fs.existsSync(path.join(this.projectRoot, 'artisan'))) {
            context.type = 'laravel';
        }
        else if (fs.existsSync(path.join(this.projectRoot, 'composer.json'))) {
            context.type = 'php-composer';
            try {
                const composer = JSON.parse(fs.readFileSync(path.join(this.projectRoot, 'composer.json'), 'utf-8'));
                context.dependencies = composer.require || {};
            }
            catch { /* ignore parse errors */ }
        }
        // Get relevant files
        const allFiles = await this.listFiles();
        context.files = allFiles.slice(0, maxFiles);
        return context;
    }
    // Create diff
    createDiff(original, modified) {
        const originalLines = original.split('\n');
        const modifiedLines = modified.split('\n');
        const added = [];
        const removed = [];
        // Simple diff - for display purposes
        const maxLen = Math.max(originalLines.length, modifiedLines.length);
        for (let i = 0; i < maxLen; i++) {
            const origLine = originalLines[i];
            const modLine = modifiedLines[i];
            if (origLine !== modLine) {
                if (origLine !== undefined) {
                    removed.push(`${i + 1}: ${origLine}`);
                }
                if (modLine !== undefined) {
                    added.push(`${i + 1}: ${modLine}`);
                }
            }
        }
        return { added, removed };
    }
}
