/**
 * Per-US JIRA Sync (v0.34.0+)
 *
 * Syncs each User Story to its explicitly declared project's JIRA project.
 * Uses the **Project**: field in spec.md (NOT keyword-based classification).
 *
 * Key difference from multi-project-sync:
 * - Multi-project sync uses keyword/heuristic classification
 * - Per-US sync uses EXPLICIT **Project**: field from spec.md
 *
 * @module per-us-sync
 * @since v0.34.0
 */
import { consoleLogger } from '../../../../../src/utils/logger.js';
/**
 * Per-US JIRA Sync
 *
 * Syncs each US to its declared project's JIRA project.
 */
export class PerUSJiraSync {
    constructor(jiraClient, projectMappings, options = {}) {
        this.jiraClient = jiraClient;
        this.projectMappings = projectMappings;
        this.logger = options.logger ?? consoleLogger;
    }
    /**
     * Sync all user stories to their respective JIRA projects
     *
     * @param userStories - User stories with explicit project fields
     * @param featureId - Feature ID (e.g., "FS-137")
     * @param options - Sync options
     */
    async syncUserStories(userStories, featureId, options = {}) {
        const synced = [];
        const failed = [];
        const externalRefs = {};
        // Group USs by their declared project
        const groups = this.groupByProject(userStories, options.defaultProject);
        this.logger.log(`📡 Per-US JIRA Sync: ${userStories.length} USs across ${groups.size} projects`);
        for (const [projectId, stories] of groups) {
            // Get JIRA mapping for this project
            const mapping = this.projectMappings[projectId]?.jira;
            if (!mapping) {
                // No JIRA mapping for this project
                this.logger.warn(`   ⚠️  No JIRA mapping for project "${projectId}" - skipping ${stories.length} USs`);
                for (const story of stories) {
                    failed.push({
                        usId: story.id,
                        projectId,
                        jiraProject: 'N/A',
                        issueKey: '',
                        url: '',
                        action: 'skipped',
                        error: `No JIRA mapping for project "${projectId}"`
                    });
                }
                continue;
            }
            // Sync each US to this project's JIRA project
            for (const story of stories) {
                try {
                    const result = await this.syncUserStory(story, mapping, featureId, options);
                    synced.push({
                        ...result,
                        projectId
                    });
                    // Build external ref
                    if (!options.dryRun && result.action !== 'skipped') {
                        externalRefs[story.id] = {
                            jira: {
                                provider: 'jira',
                                issueNumber: result.issueKey,
                                url: result.url,
                                targetProject: projectId,
                                lastSynced: new Date().toISOString()
                            }
                        };
                    }
                }
                catch (error) {
                    failed.push({
                        usId: story.id,
                        projectId,
                        jiraProject: mapping.project,
                        issueKey: '',
                        url: '',
                        action: 'skipped',
                        error: error instanceof Error ? error.message : String(error)
                    });
                }
            }
        }
        // Calculate summary
        const created = synced.filter(r => r.action === 'created').length;
        const updated = synced.filter(r => r.action === 'updated').length;
        const skipped = synced.filter(r => r.action === 'skipped').length;
        return {
            success: failed.length === 0,
            synced,
            failed,
            externalRefs,
            summary: {
                total: userStories.length,
                created,
                updated,
                skipped,
                failed: failed.length
            }
        };
    }
    /**
     * Sync a single user story to JIRA
     */
    async syncUserStory(story, mapping, featureId, options) {
        const summary = `[${featureId}][${story.id}] ${story.title}`;
        const description = this.buildIssueDescription(story, featureId);
        if (options.dryRun) {
            this.logger.log(`   🔍 [DRY-RUN] Would sync ${story.id} to JIRA project ${mapping.project}`);
            return {
                usId: story.id,
                projectId: story.project || 'unknown',
                jiraProject: mapping.project,
                issueKey: '',
                url: '',
                action: 'skipped'
            };
        }
        // Check for existing issue
        const existingIssue = await this.findExistingIssue(mapping.project, story.id);
        if (existingIssue) {
            // Update existing issue
            await this.jiraClient.updateIssue(existingIssue.key, summary, description);
            this.logger.log(`   🔄 Updated ${story.id} → ${existingIssue.key}`);
            return {
                usId: story.id,
                projectId: story.project || 'unknown',
                jiraProject: mapping.project,
                issueKey: existingIssue.key,
                url: this.jiraClient.getIssueUrl(existingIssue.key),
                action: 'updated'
            };
        }
        else {
            // Create new issue
            const newIssue = await this.jiraClient.createIssue(mapping.project, 'Story', summary, description);
            this.logger.log(`   ✅ Created ${story.id} → ${newIssue.key}`);
            return {
                usId: story.id,
                projectId: story.project || 'unknown',
                jiraProject: mapping.project,
                issueKey: newIssue.key,
                url: this.jiraClient.getIssueUrl(newIssue.key),
                action: 'created'
            };
        }
    }
    /**
     * Find existing issue by US ID in summary
     */
    async findExistingIssue(project, usId) {
        try {
            const jql = `project = "${project}" AND summary ~ "[${usId}]"`;
            const results = await this.jiraClient.searchIssues(jql);
            return results.length > 0 ? { key: results[0].key } : null;
        }
        catch {
            return null;
        }
    }
    /**
     * Build issue description from user story
     *
     * Includes full User Story format with description and Acceptance Criteria.
     * Uses `acceptanceCriteriaFull` if available (v1.0.59+) for AC descriptions,
     * otherwise falls back to AC IDs only.
     */
    buildIssueDescription(story, featureId) {
        const lines = [];
        lines.push(`h1. ${story.title}`);
        lines.push('');
        // User Story description (As a... I want... So that...)
        if (story.description) {
            // Convert markdown bold to JIRA formatting
            const jiraDesc = story.description
                .replace(/\*\*As a\*\*/g, '*As a*')
                .replace(/\*\*I want\*\*/g, '*I want*')
                .replace(/\*\*So that\*\*/g, '*So that*');
            lines.push(jiraDesc);
            lines.push('');
        }
        // Acceptance Criteria - prefer full descriptions if available
        if (story.acceptanceCriteriaFull && story.acceptanceCriteriaFull.length > 0) {
            // Use full AC data with descriptions (v1.0.59+)
            lines.push('h2. Acceptance Criteria');
            lines.push('');
            for (const ac of story.acceptanceCriteriaFull) {
                const checkbox = ac.completed ? '(/)' : '(x)';
                lines.push(`* ${checkbox} *${ac.id}*: ${ac.description}`);
            }
            lines.push('');
        }
        else if (story.acceptanceCriteria && story.acceptanceCriteria.length > 0) {
            // Fallback: AC IDs only (backward compatible)
            lines.push('h2. Acceptance Criteria');
            lines.push('');
            for (const ac of story.acceptanceCriteria) {
                lines.push(`* (x) ${ac}`);
            }
            lines.push('');
        }
        lines.push('----');
        lines.push('');
        lines.push(`*Feature*: ${featureId}`);
        lines.push(`*User Story*: ${story.id}`);
        if (story.project) {
            lines.push(`*Project*: ${story.project}`);
        }
        if (story.board) {
            lines.push(`*Board*: ${story.board}`);
        }
        return lines.join('\n');
    }
    /**
     * Group user stories by their explicit project field
     */
    groupByProject(userStories, defaultProject) {
        const groups = new Map();
        for (const story of userStories) {
            const project = story.project || defaultProject || 'default';
            if (!groups.has(project)) {
                groups.set(project, []);
            }
            groups.get(project).push(story);
        }
        return groups;
    }
}
/**
 * Format per-US sync results for display
 */
export function formatPerUSSyncResults(result) {
    const lines = [];
    lines.push('');
    lines.push('📊 Per-US JIRA Sync Results');
    lines.push('');
    // Group by project
    const byProject = new Map();
    for (const r of [...result.synced, ...result.failed]) {
        const existing = byProject.get(r.projectId) || [];
        existing.push(r);
        byProject.set(r.projectId, existing);
    }
    for (const [projectId, results] of byProject) {
        lines.push(`**${projectId}** (→ ${results[0]?.jiraProject || 'N/A'}):`);
        for (const r of results) {
            const icon = r.action === 'created' ? '✅' :
                r.action === 'updated' ? '🔄' :
                    r.error ? '❌' : '⏭️';
            if (r.issueKey) {
                lines.push(`  ${icon} ${r.usId} → ${r.issueKey}`);
            }
            else if (r.error) {
                lines.push(`  ${icon} ${r.usId}: ${r.error}`);
            }
            else {
                lines.push(`  ${icon} ${r.usId} (${r.action})`);
            }
        }
        lines.push('');
    }
    lines.push(`📈 Summary: ${result.summary.created} created, ${result.summary.updated} updated, ${result.summary.failed} failed`);
    return lines.join('\n');
}
//# sourceMappingURL=per-us-sync.js.map