import { promises as fs } from 'fs';
import path from 'path';
export class IssueTracker {
    configManager;
    issuesPath;
    templatesPath;
    milestonesPath;
    constructor(configManager) {
        this.configManager = configManager;
        this.issuesPath = '';
        this.templatesPath = '';
        this.milestonesPath = '';
    }
    async init() {
        const storageManager = this.configManager.getStorageManager();
        const location = await storageManager.getStorageLocation();
        const dataPath = path.join(location.data, 'issue-tracking');
        this.issuesPath = path.join(dataPath, 'issues');
        this.templatesPath = path.join(dataPath, 'templates');
        this.milestonesPath = path.join(dataPath, 'milestones');
        await this.ensureDirectories();
        await this.createDefaultTemplates();
    }
    async ensureDirectories() {
        await fs.mkdir(this.issuesPath, { recursive: true });
        await fs.mkdir(this.templatesPath, { recursive: true });
        await fs.mkdir(this.milestonesPath, { recursive: true });
    }
    async createIssue(data) {
        const issue = {
            id: this.generateId(),
            type: data.type,
            title: data.title,
            description: data.description,
            status: 'open',
            priority: data.priority,
            createdAt: new Date().toISOString(),
            createdBy: data.createdBy,
            updatedAt: new Date().toISOString(),
            assignedTo: data.assignedTo,
            labels: data.labels || [],
            affectedModules: data.affectedModules || [],
            relatedIssues: [],
            attachments: [],
            comments: []
        };
        await this.saveIssue(issue);
        return issue;
    }
    async updateIssue(issueId, updates) {
        const issue = await this.getIssue(issueId);
        const updatedIssue = {
            ...issue,
            ...updates,
            id: issue.id,
            createdAt: issue.createdAt,
            createdBy: issue.createdBy,
            updatedAt: new Date().toISOString()
        };
        if (updates.status === 'resolved' || updates.status === 'closed') {
            updatedIssue.closedAt = new Date().toISOString();
        }
        await this.saveIssue(updatedIssue);
        return updatedIssue;
    }
    async addComment(issueId, data) {
        const issue = await this.getIssue(issueId);
        const comment = {
            id: this.generateId(),
            issueId,
            author: data.author,
            content: data.content,
            createdAt: new Date().toISOString(),
            type: data.type || 'comment'
        };
        issue.comments.push(comment);
        issue.updatedAt = new Date().toISOString();
        await this.saveIssue(issue);
        return comment;
    }
    async searchIssues(filter) {
        const allIssues = await this.getAllIssues();
        return allIssues.filter(issue => {
            if (filter.type && !filter.type.includes(issue.type))
                return false;
            if (filter.status && !filter.status.includes(issue.status))
                return false;
            if (filter.priority && !filter.priority.includes(issue.priority))
                return false;
            if (filter.assignedTo && issue.assignedTo !== filter.assignedTo)
                return false;
            if (filter.createdBy && issue.createdBy !== filter.createdBy)
                return false;
            if (filter.labels && filter.labels.length > 0) {
                const hasAllLabels = filter.labels.every(label => issue.labels.includes(label));
                if (!hasAllLabels)
                    return false;
            }
            if (filter.affectedModules && filter.affectedModules.length > 0) {
                const hasModule = filter.affectedModules.some(module => issue.affectedModules.includes(module));
                if (!hasModule)
                    return false;
            }
            if (filter.dateRange) {
                const createdDate = new Date(issue.createdAt);
                const startDate = new Date(filter.dateRange.start);
                const endDate = new Date(filter.dateRange.end);
                if (createdDate < startDate || createdDate > endDate)
                    return false;
            }
            if (filter.searchQuery) {
                const query = filter.searchQuery.toLowerCase();
                const searchableText = `${issue.title} ${issue.description} ${issue.comments.map(c => c.content).join(' ')}`.toLowerCase();
                if (!searchableText.includes(query))
                    return false;
            }
            return true;
        });
    }
    async getIssueStats(filter) {
        const issues = filter ? await this.searchIssues(filter) : await this.getAllIssues();
        const stats = {
            total: issues.length,
            byType: {
                bug: 0,
                feature: 0,
                enhancement: 0,
                documentation: 0,
                question: 0
            },
            byStatus: {
                open: 0,
                'in-progress': 0,
                resolved: 0,
                closed: 0,
                'wont-fix': 0
            },
            byPriority: {
                critical: 0,
                high: 0,
                medium: 0,
                low: 0
            },
            averageResolutionTime: 0,
            trends: {
                period: 'weekly',
                opened: [],
                closed: []
            }
        };
        let totalResolutionTime = 0;
        let resolvedCount = 0;
        let oldestOpen;
        for (const issue of issues) {
            stats.byType[issue.type]++;
            stats.byStatus[issue.status]++;
            stats.byPriority[issue.priority]++;
            if (issue.closedAt) {
                const resolutionTime = new Date(issue.closedAt).getTime() - new Date(issue.createdAt).getTime();
                totalResolutionTime += resolutionTime;
                resolvedCount++;
            }
            if (issue.status === 'open' && (!oldestOpen || issue.createdAt < oldestOpen.createdAt)) {
                oldestOpen = issue;
            }
        }
        stats.averageResolutionTime = resolvedCount > 0 ? totalResolutionTime / resolvedCount : 0;
        stats.oldestOpenIssue = oldestOpen;
        const moduleCounts = {};
        for (const issue of issues) {
            for (const module of issue.affectedModules) {
                moduleCounts[module] = (moduleCounts[module] || 0) + 1;
            }
        }
        const sortedModules = Object.entries(moduleCounts).sort((a, b) => b[1] - a[1]);
        if (sortedModules.length > 0) {
            stats.mostActiveModule = sortedModules[0][0];
        }
        return stats;
    }
    async createMilestone(data) {
        const milestone = {
            id: this.generateId(),
            title: data.title,
            description: data.description,
            dueDate: data.dueDate,
            status: new Date(data.dueDate) > new Date() ? 'active' : 'overdue',
            issues: data.issues || [],
            progress: {
                total: 0,
                completed: 0,
                percentage: 0
            }
        };
        await this.updateMilestoneProgress(milestone);
        await this.saveMilestone(milestone);
        return milestone;
    }
    async updateMilestoneProgress(milestone) {
        const issues = await Promise.all(milestone.issues.map(id => this.getIssue(id).catch(() => null)));
        const validIssues = issues.filter(Boolean);
        const completedIssues = validIssues.filter(i => i.status === 'resolved' || i.status === 'closed');
        milestone.progress = {
            total: validIssues.length,
            completed: completedIssues.length,
            percentage: validIssues.length > 0
                ? Math.round((completedIssues.length / validIssues.length) * 100)
                : 0
        };
    }
    async createDefaultTemplates() {
        const bugTemplate = {
            type: 'bug',
            name: 'Bug Report',
            description: 'Report a bug or unexpected behavior',
            sections: [
                {
                    title: 'Description',
                    prompt: 'A clear description of the bug',
                    required: true,
                    type: 'multiline'
                },
                {
                    title: 'Steps to Reproduce',
                    prompt: 'Step-by-step instructions to reproduce the issue',
                    required: true,
                    type: 'multiline'
                },
                {
                    title: 'Expected Behavior',
                    prompt: 'What should happen',
                    required: true,
                    type: 'text'
                },
                {
                    title: 'Actual Behavior',
                    prompt: 'What actually happens',
                    required: true,
                    type: 'text'
                },
                {
                    title: 'Environment',
                    prompt: 'OS, Node version, etc.',
                    required: false,
                    type: 'multiline'
                }
            ],
            defaultLabels: ['bug'],
            defaultPriority: 'medium'
        };
        const featureTemplate = {
            type: 'feature',
            name: 'Feature Request',
            description: 'Suggest a new feature',
            sections: [
                {
                    title: 'Feature Description',
                    prompt: 'Describe the feature you would like',
                    required: true,
                    type: 'multiline'
                },
                {
                    title: 'Use Case',
                    prompt: 'Why is this feature needed?',
                    required: true,
                    type: 'multiline'
                },
                {
                    title: 'Proposed Solution',
                    prompt: 'How might this work?',
                    required: false,
                    type: 'multiline'
                },
                {
                    title: 'Alternatives',
                    prompt: 'Have you considered any alternatives?',
                    required: false,
                    type: 'multiline'
                }
            ],
            defaultLabels: ['enhancement'],
            defaultPriority: 'medium'
        };
        await this.saveTemplate(bugTemplate);
        await this.saveTemplate(featureTemplate);
    }
    async getIssue(issueId) {
        const issuePath = path.join(this.issuesPath, `${issueId}.json`);
        const content = await fs.readFile(issuePath, 'utf-8');
        return JSON.parse(content);
    }
    async getAllIssues() {
        try {
            const files = await fs.readdir(this.issuesPath);
            const issues = await Promise.all(files
                .filter(f => f.endsWith('.json'))
                .map(async (f) => {
                const content = await fs.readFile(path.join(this.issuesPath, f), 'utf-8');
                return JSON.parse(content);
            }));
            return issues;
        }
        catch {
            return [];
        }
    }
    async saveIssue(issue) {
        const issuePath = path.join(this.issuesPath, `${issue.id}.json`);
        await fs.writeFile(issuePath, JSON.stringify(issue, null, 2));
    }
    async saveMilestone(milestone) {
        const milestonePath = path.join(this.milestonesPath, `${milestone.id}.json`);
        await fs.writeFile(milestonePath, JSON.stringify(milestone, null, 2));
    }
    async saveTemplate(template) {
        const templatePath = path.join(this.templatesPath, `${template.type}.json`);
        await fs.writeFile(templatePath, JSON.stringify(template, null, 2));
    }
    generateId() {
        return `issue_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    }
}
//# sourceMappingURL=issue-tracker.js.map