// fileHeaderManager.js
import fs from 'fs/promises';
import path from 'path';

class FileHeaderManager {
    static COMMENT_CONFIG = {
        '.js': {
            start: '/*',
            end: '*/',
            // 修改正则表达式，确保只匹配文件开头的注释块
            regex: /^(\s*\/\*[\s\S]*?\*\/)/,
            headerRegex: /@header\(([\s\S]*?)\)/,
            createComment: (content) => `/*\n${content}\n*/`,
            topCommentsRegex: /^(\s*(\/\/[^\n]*\n|\/\*[\s\S]*?\*\/)\s*)+/
        },
        '.py': {
            start: '"""',
            end: '"""',
            // 修改正则表达式，确保只匹配文件开头的注释块
            regex: /^(\s*"""[\s\S]*?""")/,
            headerRegex: /@header\(([\s\S]*?)\)/,
            createComment: (content) => `"""\n${content}\n"""`,
            topCommentsRegex: /^(\s*(#[^\n]*\n|'''[\s\S]*?'''|"""[\s\S]*?""")\s*)+/
        }
    };

    /**
     * 解析JavaScript对象字面量（支持无引号属性名）
     * @param {string} str 对象字符串
     * @returns {Object} 解析后的对象
     */
    static parseObjectLiteral(str) {
        const normalized = str
            .replace(/([{,]\s*)([a-zA-Z_$][\w$]*)(\s*:)/g, '$1"$2"$3')
            .replace(/'([^']+)'/g, '"$1"');

        try {
            return JSON.parse(normalized);
        } catch (e) {
            try {
                return (new Function(`return ${str}`))();
            } catch {
                throw new Error(`Invalid header object: ${str}`);
            }
        }
    }

    /**
     * 读取文件头信息
     * @param {string} filePath 文件路径
     * @returns {Object|null} 头信息对象
     */
    static async readHeader(filePath) {
        const content = await fs.readFile(filePath, 'utf8');
        const ext = path.extname(filePath);
        const config = this.COMMENT_CONFIG[ext];

        if (!config) throw new Error(`Unsupported file type: ${ext}`);

        const match = content.match(config.regex);
        if (!match) return null;

        const headerMatch = match[0].match(config.headerRegex);
        if (!headerMatch) return null;

        try {
            return this.parseObjectLiteral(headerMatch[1].trim());
        } catch {
            return null;
        }
    }

    /**
     * 创建文件备份
     * @param {string} filePath 原文件路径
     * @returns {string} 备份文件路径
     */
    static async createBackup(filePath) {
        const backupPath = `${filePath}.backup.${Date.now()}`;
        try {
            const content = await fs.readFile(filePath, 'utf8');
            await fs.writeFile(backupPath, content);
            return backupPath;
        } catch (error) {
            throw new Error(`Failed to create backup: ${error.message}`);
        }
    }

    /**
     * 从备份恢复文件
     * @param {string} filePath 目标文件路径
     * @param {string} backupPath 备份文件路径
     */
    static async restoreFromBackup(filePath, backupPath) {
        try {
            const backupContent = await fs.readFile(backupPath, 'utf8');
            await fs.writeFile(filePath, backupContent);
            // 删除备份文件
            await fs.unlink(backupPath);
        } catch (error) {
            throw new Error(`Failed to restore from backup: ${error.message}`);
        }
    }

    /**
     * 写入/更新文件头信息
     * @param {string} filePath 文件路径
     * @param {Object} headerObj 头信息对象
     * @param {Object} [options] 配置选项
     * @param {boolean} [options.createBackup=true] 是否创建备份
     */
    static async writeHeader(filePath, headerObj, options = {}) {
        const {createBackup = false} = options;
        // 添加参数验证
        if (!filePath || typeof filePath !== 'string') {
            throw new Error('Invalid file path');
        }
        if (!headerObj || typeof headerObj !== 'object') {
            throw new Error('Invalid header object');
        }

        let content;
        try {
            content = await fs.readFile(filePath, 'utf8');
        } catch (error) {
            throw new Error(`Failed to read file: ${error.message}`);
        }

        // 备份原始内容
        const originalContent = content;
        const ext = path.extname(filePath);
        const config = this.COMMENT_CONFIG[ext];

        if (!config) throw new Error(`Unsupported file type: ${ext}`);

        const headerStr = `@header(${JSON.stringify(headerObj, null, 2)
            .replace(/"([a-zA-Z_$][\w$]*)":/g, '$1:')
            .replace(/"/g, "'")})`;

        const match = content.match(config.regex);
        let newContent;

        if (match) {
            const [fullComment] = match;
            const commentStartIndex = content.indexOf(fullComment);
            const commentEndIndex = commentStartIndex + fullComment.length;

            // 确保匹配的注释块确实在文件开头（允许前面有空白字符）
            const beforeComment = content.substring(0, commentStartIndex);
            if (beforeComment.trim() !== '') {
                // 如果注释块前面有非空白内容，说明这不是文件头注释，创建新的头注释
                const newComment = config.createComment(headerStr) + '\n\n';
                newContent = newComment + content;
            } else {
                // 这是文件头注释，进行更新
                if (config.headerRegex.test(fullComment)) {
                    // 已存在@header，替换它
                    const updatedComment = fullComment.replace(config.headerRegex, headerStr);
                    newContent = content.substring(0, commentStartIndex) +
                        updatedComment +
                        content.substring(commentEndIndex);
                } else {
                    // 不存在@header，添加到注释块中
                    const updatedComment = fullComment
                            .replace(config.end, '')
                            .trim()
                        + `\n${headerStr}\n${config.end}`;
                    newContent = content.substring(0, commentStartIndex) +
                        updatedComment +
                        content.substring(commentEndIndex);
                }
            }
        } else {
            // 没有找到注释块，在文件开头创建新的
            const newComment = config.createComment(headerStr) + '\n\n';
            newContent = newComment + content;
        }

        // 确保新内容不只包含文件头
        const contentWithoutHeader = newContent.replace(config.regex, '').trim();
        if (!contentWithoutHeader) {
            throw new Error('写入失败：内容不能只包含文件头而无原始内容');
        }

        // 验证新内容不为空且包含原始内容的主要部分
        if (!newContent || newContent.trim().length === 0) {
            throw new Error('Generated content is empty, operation aborted');
        }

        // 简单的内容完整性检查：确保新内容包含原始内容的大部分非注释代码
        const originalCodeLines = originalContent.split('\n').filter(line => {
            const trimmed = line.trim();
            return trimmed && !trimmed.startsWith('//') && !trimmed.startsWith('/*') &&
                !trimmed.startsWith('*') && !trimmed.startsWith('*/') &&
                !trimmed.startsWith('#') && !trimmed.startsWith('"""') && !trimmed.startsWith("'''");
        });

        const newCodeLines = newContent.split('\n').filter(line => {
            const trimmed = line.trim();
            return trimmed && !trimmed.startsWith('//') && !trimmed.startsWith('/*') &&
                !trimmed.startsWith('*') && !trimmed.startsWith('*/') &&
                !trimmed.startsWith('#') && !trimmed.startsWith('"""') && !trimmed.startsWith("'''") &&
                !trimmed.includes('@header(');
        });

        // 如果新内容的代码行数比原始内容少了很多，可能出现了问题
        if (originalCodeLines.length > 5 && newCodeLines.length < originalCodeLines.length * 0.8) {
            throw new Error('Content integrity check failed: significant code loss detected, operation aborted');
        }

        // 创建备份（如果启用）
        let backupPath = null;
        if (createBackup) {
            try {
                backupPath = await this.createBackup(filePath);
            } catch (error) {
                console.warn(`Warning: Failed to create backup for ${filePath}: ${error.message}`);
            }
        }

        try {
            await fs.writeFile(filePath, newContent);

            // 写入成功后，删除备份文件
            if (backupPath) {
                try {
                    await fs.unlink(backupPath);
                } catch (error) {
                    console.warn(`Warning: Failed to delete backup file ${backupPath}: ${error.message}`);
                }
            }
        } catch (error) {
            // 写入失败，尝试从备份恢复
            if (backupPath) {
                try {
                    await this.restoreFromBackup(filePath, backupPath);
                    console.log(`File restored from backup: ${filePath}`);
                } catch (restoreError) {
                    console.error(`Failed to restore from backup: ${restoreError.message}`);
                }
            }
            throw new Error(`Failed to write file: ${error.message}`);
        }
    }

    /**
     * 移除头信息区域
     * @param {string} input 文件路径或文件内容
     * @param {Object} [options] 配置选项
     * @param {string} [options.mode='header-only'] 移除模式:
     *   - 'header-only': 只移除@header行（默认）
     *   - 'top-comments': 移除文件顶部所有连续注释块
     * @param {string} [options.fileType] 文件类型（当input为内容时必需）
     * @returns {Promise<string>|string} 移除头信息后的内容
     */
    static async removeHeader(input, options = {}) {
        const {mode = 'header-only', fileType} = options;

        // 判断输入类型：文件路径 or 文件内容
        const isFilePath = !input.includes('\n') && input.length < 256 &&
            (input.endsWith('.js') || input.endsWith('.py'));

        let content, ext;

        if (isFilePath) {
            content = await fs.readFile(input, 'utf8');
            ext = path.extname(input);
        } else {
            content = input;
            ext = fileType ? `.${fileType.replace(/^\./, '')}` : null;

            if (!ext) {
                throw new Error('fileType option is required when input is content');
            }
        }

        const config = this.COMMENT_CONFIG[ext];
        if (!config) throw new Error(`Unsupported file type: ${ext}`);

        // 模式1: 移除顶部所有连续注释块
        if (mode === 'top-comments') {
            const match = content.match(config.topCommentsRegex);
            if (match) {
                content = content.substring(match[0].length);
            }
            return content.trim();
        }

        // 模式2: 只移除@header行（默认模式）
        const match = content.match(config.regex);
        if (!match) return content.trim();

        let [fullComment, innerContent] = match;

        if (config.headerRegex.test(innerContent)) {
            innerContent = innerContent.replace(config.headerRegex, '');

            const cleanedInner = innerContent
                .split('\n')
                .filter(line => line.trim().length > 0)
                .join('\n');

            if (!cleanedInner.trim()) {
                content = content.replace(fullComment, '');
            } else {
                const newComment = `${config.start}${cleanedInner}${config.end}`;
                content = content.replace(fullComment, newComment);
            }
        }

        return content.trim();
    }

    /**
     * 获取文件大小
     * @param {string} filePath 文件路径
     * @param {Object} [options] 配置选项
     * @param {boolean} [options.humanReadable=false] 是否返回人类可读格式
     * @returns {Promise<number|string>} 文件大小（字节或人类可读字符串）
     */
    static async getFileSize(filePath, options = {}) {
        try {
            const stats = await fs.stat(filePath);
            const sizeInBytes = stats.size;

            if (options.humanReadable) {
                return this.formatFileSize(sizeInBytes);
            }
            return sizeInBytes;
        } catch (error) {
            throw new Error(`获取文件大小失败: ${error.message}`);
        }
    }

    /**
     * 格式化文件大小为人类可读格式
     * @param {number} bytes 文件大小（字节）
     * @returns {string} 格式化后的文件大小
     */
    static formatFileSize(bytes) {
        if (bytes === 0) return '0 Bytes';

        const k = 1024;
        const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
        const i = Math.floor(Math.log(bytes) / Math.log(k));

        return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
    }
}

export default FileHeaderManager;