import { EventEmitter } from 'events';
import { promises as fs } from 'fs';
import { join, isAbsolute } from 'path';
import chokidar from 'chokidar';
import { PathUtils } from '../core/path-utils.js';
export class ApprovalStorage extends EventEmitter {
    projectPath; // Make public so dashboard server can access it
    approvalsDir;
    watcher;
    constructor(projectPath) {
        super();
        this.projectPath = projectPath;
        this.approvalsDir = PathUtils.getApprovalsPath(projectPath);
    }
    async start() {
        // Create the approvals directory (empty) so watcher can establish properly
        await fs.mkdir(this.approvalsDir, { recursive: true });
        // Set up file watcher for approval directory and all subdirectories
        // This will catch new directories and files created dynamically
        this.watcher = chokidar.watch(`${this.approvalsDir}/**/*.json`, {
            ignoreInitial: false,
            persistent: true,
            ignorePermissionErrors: true
        });
        this.watcher.on('add', () => this.emit('approval-change'));
        this.watcher.on('change', () => this.emit('approval-change'));
        this.watcher.on('unlink', () => this.emit('approval-change'));
    }
    async stop() {
        if (this.watcher) {
            // Remove all listeners before closing to prevent memory leaks
            this.watcher.removeAllListeners();
            await this.watcher.close();
            this.watcher = undefined;
        }
        // Clean up EventEmitter listeners
        this.removeAllListeners();
    }
    async createApproval(title, filePath, category, categoryName, type = 'document', metadata) {
        const id = this.generateId();
        const approval = {
            id,
            title,
            filePath,
            type,
            status: 'pending',
            createdAt: new Date().toISOString(),
            metadata,
            category,
            categoryName
        };
        // Create category directory if it doesn't exist
        const categoryDir = join(this.approvalsDir, categoryName);
        await fs.mkdir(categoryDir, { recursive: true });
        const approvalFilePath = join(categoryDir, `${id}.json`);
        await fs.writeFile(approvalFilePath, JSON.stringify(approval, null, 2), 'utf-8');
        return id;
    }
    async getApproval(id) {
        // Search across all categories and names
        try {
            const approvalPath = await this.findApprovalPath(id);
            if (!approvalPath)
                return null;
            const content = await fs.readFile(approvalPath, 'utf-8');
            return JSON.parse(content);
        }
        catch {
            return null;
        }
    }
    async findApprovalPath(id) {
        // Search in approvals directory directly (no 'specs' subfolder)
        try {
            const categoryNames = await fs.readdir(this.approvalsDir, { withFileTypes: true });
            for (const categoryName of categoryNames) {
                if (categoryName.isDirectory()) {
                    const approvalPath = join(this.approvalsDir, categoryName.name, `${id}.json`);
                    try {
                        await fs.access(approvalPath);
                        return approvalPath;
                    }
                    catch {
                        // File doesn't exist in this location, continue searching
                    }
                }
            }
        }
        catch {
            // Approvals directory doesn't exist
        }
        return null;
    }
    async updateApproval(id, status, response, annotations, comments) {
        const approval = await this.getApproval(id);
        if (!approval) {
            throw new Error(`Approval ${id} not found`);
        }
        approval.status = status;
        approval.response = response;
        approval.annotations = annotations;
        approval.respondedAt = new Date().toISOString();
        if (comments) {
            approval.comments = comments;
        }
        const filePath = await this.findApprovalPath(id);
        if (!filePath) {
            throw new Error(`Approval ${id} file not found`);
        }
        await fs.writeFile(filePath, JSON.stringify(approval, null, 2), 'utf-8');
    }
    async createRevision(originalId, newContent, reason) {
        const originalApproval = await this.getApproval(originalId);
        if (!originalApproval) {
            throw new Error(`Original approval ${originalId} not found`);
        }
        if (!originalApproval.filePath) {
            throw new Error(`Approval ${originalId} has no file path for revision`);
        }
        // Read the current file content for revision history
        const filePath = isAbsolute(originalApproval.filePath)
            ? originalApproval.filePath
            : join(this.projectPath, originalApproval.filePath);
        let currentContent = '';
        try {
            currentContent = await fs.readFile(filePath, 'utf-8');
        }
        catch (error) {
            // Could not read file for revision history
        }
        // Add to revision history
        if (!originalApproval.revisionHistory) {
            originalApproval.revisionHistory = [];
        }
        const version = (originalApproval.revisionHistory.length || 0) + 1;
        originalApproval.revisionHistory.push({
            version: version - 1,
            content: currentContent,
            timestamp: originalApproval.respondedAt || originalApproval.createdAt,
            reason: reason
        });
        // Write the new content to the file
        await fs.writeFile(filePath, newContent, 'utf-8');
        // Reset approval status for re-review
        originalApproval.status = 'pending';
        originalApproval.response = undefined;
        originalApproval.annotations = undefined;
        originalApproval.comments = undefined;
        originalApproval.respondedAt = undefined;
        const approvalFilePath = await this.findApprovalPath(originalId);
        if (!approvalFilePath) {
            throw new Error(`Approval ${originalId} file not found`);
        }
        await fs.writeFile(approvalFilePath, JSON.stringify(originalApproval, null, 2), 'utf-8');
        return originalId;
    }
    async getAllPendingApprovals() {
        const allApprovals = await this.getAllApprovals();
        return allApprovals.filter(approval => approval.status === 'pending');
    }
    async getAllApprovals() {
        try {
            const approvals = [];
            try {
                const categoryNames = await fs.readdir(this.approvalsDir, { withFileTypes: true });
                for (const categoryName of categoryNames) {
                    if (categoryName.isDirectory()) {
                        const categoryPath = join(this.approvalsDir, categoryName.name);
                        try {
                            const approvalFiles = await fs.readdir(categoryPath);
                            for (const file of approvalFiles) {
                                if (file.endsWith('.json')) {
                                    try {
                                        const content = await fs.readFile(join(categoryPath, file), 'utf-8');
                                        const approval = JSON.parse(content);
                                        approvals.push(approval);
                                    }
                                    catch (error) {
                                        // Error reading approval file
                                    }
                                }
                            }
                        }
                        catch (error) {
                            // Error reading category directory
                        }
                    }
                }
            }
            catch {
                // Approvals directory doesn't exist
            }
            // Sort by creation date (newest first)
            return approvals.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
        }
        catch {
            return [];
        }
    }
    async deleteApproval(id) {
        try {
            const approvalPath = await this.findApprovalPath(id);
            if (!approvalPath)
                return false;
            await fs.unlink(approvalPath);
            return true;
        }
        catch {
            return false;
        }
    }
    async cleanupOldApprovals(maxAgeDays = 7) {
        const cutoffDate = new Date();
        cutoffDate.setDate(cutoffDate.getDate() - maxAgeDays);
        try {
            const files = await fs.readdir(this.approvalsDir);
            for (const file of files) {
                if (file.endsWith('.json')) {
                    try {
                        const content = await fs.readFile(join(this.approvalsDir, file), 'utf-8');
                        const approval = JSON.parse(content);
                        const createdAt = new Date(approval.createdAt);
                        if (createdAt < cutoffDate && approval.status !== 'pending') {
                            await fs.unlink(join(this.approvalsDir, file));
                        }
                    }
                    catch (error) {
                        // Error processing approval file
                    }
                }
            }
        }
        catch (error) {
            // Error cleaning up old approvals
        }
    }
    generateId() {
        return `approval_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    }
}
//# sourceMappingURL=approval-storage.js.map