/**
 * Azure DevOps API Client
 *
 * Supports:
 * 1. MCP Server (microsoft/azure-devops-mcp) - Primary
 * 2. REST API - Fallback
 *
 * Features:
 * - List work items with filtering (by sprint, status, etc.)
 * - Create work items (Epic, Feature, User Story, Task)
 * - Update work items
 * - Get sprint/iteration information
 */
import { credentialsManager } from '../../core/credentials/credentials-manager.js';
import { consoleLogger } from '../../utils/logger.js';
/**
 * Module logger - can be replaced for testing
 */
let moduleLogger = consoleLogger;
/**
 * Set the logger for this module
 */
export function setAdoClientLogger(logger) {
    moduleLogger = logger;
}
export class AdoClient {
    /**
     * Create ADO client
     *
     * @param config - Optional profile-specific config. If not provided,
     *                 falls back to credentials from .env (single-profile mode)
     *
     * For multi-project support, use createAdoClientForIncrement() factory
     * which resolves the increment's profile automatically.
     */
    constructor(config) {
        this.apiVersion = '7.0';
        if (config) {
            // Profile-aware mode: use provided config
            this.credentials = {
                pat: config.pat,
                organization: config.organization,
                project: config.project,
            };
        }
        else {
            // Legacy mode: use global credentials from .env
            this.credentials = credentialsManager.getAdoCredentials();
        }
        this.baseUrl = `https://dev.azure.com/${this.credentials.organization}/${this.credentials.project}`;
    }
    /**
     * Get authorization header for REST API
     */
    getAuthHeader() {
        const auth = Buffer.from(`:${this.credentials.pat}`).toString('base64');
        return `Basic ${auth}`;
    }
    /**
     * Check if response text looks like HTML (error page)
     */
    looksLikeHtml(text, contentType) {
        const trimmed = text.trim();
        return trimmed.startsWith('<!DOCTYPE') ||
            trimmed.startsWith('<html') ||
            trimmed.startsWith('<HTML') ||
            (contentType !== undefined && !contentType.includes('application/json') && text.includes('<'));
    }
    /**
     * Safely parse JSON response with HTML detection
     *
     * Azure DevOps may return HTML error pages instead of JSON when:
     * - PAT is invalid/expired
     * - Organization name is wrong
     * - Corporate proxy/firewall intercepts the request
     * - SSO redirect occurs
     *
     * @param response - Fetch response object (body must not be consumed)
     * @returns Parsed JSON data
     * @throws Error with helpful message if response is not valid JSON
     */
    async safeParseJson(response) {
        const contentType = response.headers.get('content-type') || '';
        const responseText = await response.text();
        if (this.looksLikeHtml(responseText, contentType)) {
            const possibleCauses = [
                'Invalid or expired Personal Access Token (PAT)',
                `Incorrect organization name "${this.credentials.organization}"`,
                'Corporate firewall or proxy intercepting the request',
                'SSO/authentication redirect (try accessing Azure DevOps in browser first)',
                'Network connectivity issues'
            ];
            throw new Error(`Azure DevOps returned HTML instead of JSON.\n` +
                `This usually indicates an authentication or configuration issue.\n\n` +
                `Possible causes:\n` +
                possibleCauses.map(cause => `• ${cause}`).join('\n'));
        }
        try {
            return JSON.parse(responseText);
        }
        catch {
            const preview = responseText.substring(0, 200);
            throw new Error(`Azure DevOps returned invalid JSON.\n` +
                `Response preview: ${preview}${responseText.length > 200 ? '...' : ''}`);
        }
    }
    /**
     * Handle non-OK response with helpful error messages
     *
     * @param response - Fetch response with !response.ok
     * @param context - Context for error message (e.g., "querying work items")
     * @throws Error with details
     */
    async handleErrorResponse(response, context) {
        const errorText = await response.text();
        if (this.looksLikeHtml(errorText)) {
            throw new Error(`ADO API Error (${response.status}) while ${context}.\n` +
                `Azure DevOps returned an HTML error page, which typically indicates:\n` +
                `• Invalid or expired PAT\n` +
                `• Incorrect organization/project name\n` +
                `• Corporate proxy or SSO redirect`);
        }
        throw new Error(`ADO API Error (${response.status}): ${errorText}`);
    }
    /**
     * List work items with filtering
     */
    async listWorkItems(filter = {}) {
        const wiql = this.buildWiqlQuery(filter);
        moduleLogger.info('🔍 Querying Azure DevOps with WIQL:', wiql);
        // Execute WIQL query
        const queryUrl = `${this.baseUrl}/_apis/wit/wiql?api-version=${this.apiVersion}`;
        const response = await fetch(queryUrl, {
            method: 'POST',
            headers: {
                'Authorization': this.getAuthHeader(),
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({ query: wiql })
        });
        if (!response.ok) {
            await this.handleErrorResponse(response, 'querying work items');
        }
        const queryResult = await this.safeParseJson(response);
        const workItemIds = queryResult.workItems?.map((wi) => wi.id) || [];
        if (workItemIds.length === 0) {
            moduleLogger.info('✅ No work items found matching the filter');
            return [];
        }
        // Fetch full work item details
        return this.getWorkItemsByIds(workItemIds);
    }
    /**
     * Build WIQL (Work Item Query Language) query from filter
     */
    buildWiqlQuery(filter) {
        const conditions = [
            `[System.TeamProject] = '${this.credentials.project}'`
        ];
        if (filter.workItemType && filter.workItemType.length > 0) {
            const types = filter.workItemType.map(t => `'${t}'`).join(', ');
            conditions.push(`[System.WorkItemType] IN (${types})`);
        }
        if (filter.state && filter.state.length > 0) {
            const states = filter.state.map(s => `'${s}'`).join(', ');
            conditions.push(`[System.State] IN (${states})`);
        }
        if (filter.iteration) {
            conditions.push(`[System.IterationPath] = '${filter.iteration}'`);
        }
        if (filter.areaPath) {
            conditions.push(`[System.AreaPath] = '${filter.areaPath}'`);
        }
        if (filter.assignedTo) {
            conditions.push(`[System.AssignedTo] = '${filter.assignedTo}'`);
        }
        if (filter.tags && filter.tags.length > 0) {
            filter.tags.forEach(tag => {
                conditions.push(`[System.Tags] CONTAINS '${tag}'`);
            });
        }
        // Pull sync filter: changed since timestamp
        if (filter.changedSince) {
            const isoDate = filter.changedSince.toISOString();
            conditions.push(`[System.ChangedDate] >= '${isoDate}'`);
        }
        // Pull sync filter: specific work item IDs
        if (filter.workItemIds && filter.workItemIds.length > 0) {
            const ids = filter.workItemIds.join(', ');
            conditions.push(`[System.Id] IN (${ids})`);
        }
        const whereClause = conditions.join(' AND ');
        const orderBy = 'ORDER BY [System.ChangedDate] DESC';
        const top = filter.top ? `TOP ${filter.top}` : '';
        return `SELECT ${top} [System.Id] FROM WorkItems WHERE ${whereClause} ${orderBy}`;
    }
    /**
     * Get work items by IDs
     */
    async getWorkItemsByIds(ids) {
        // ADO API supports batch retrieval of up to 200 work items
        const batchSize = 200;
        const batches = [];
        for (let i = 0; i < ids.length; i += batchSize) {
            batches.push(ids.slice(i, i + batchSize));
        }
        const allWorkItems = [];
        for (const batch of batches) {
            const idsParam = batch.join(',');
            const url = `${this.baseUrl}/_apis/wit/workitems?ids=${idsParam}&$expand=relations&api-version=${this.apiVersion}`;
            const response = await fetch(url, {
                headers: {
                    'Authorization': this.getAuthHeader(),
                    'Content-Type': 'application/json'
                }
            });
            if (!response.ok) {
                await this.handleErrorResponse(response, 'fetching work items');
            }
            const data = await this.safeParseJson(response);
            allWorkItems.push(...(data.value || []));
        }
        moduleLogger.info(`✅ Retrieved ${allWorkItems.length} work items from Azure DevOps`);
        return allWorkItems;
    }
    /**
     * Create a new work item
     */
    async createWorkItem(item) {
        moduleLogger.info(`🔨 Creating ${item.workItemType}: ${item.title}`);
        const url = `${this.baseUrl}/_apis/wit/workitems/$${item.workItemType}?api-version=${this.apiVersion}`;
        // Build JSON Patch operations
        const operations = [
            {
                op: 'add',
                path: '/fields/System.Title',
                value: item.title
            }
        ];
        if (item.description) {
            operations.push({
                op: 'add',
                path: '/fields/System.Description',
                value: item.description
            });
        }
        if (item.acceptanceCriteria) {
            operations.push({
                op: 'add',
                path: '/fields/Microsoft.VSTS.Common.AcceptanceCriteria',
                value: item.acceptanceCriteria
            });
        }
        if (item.priority !== undefined) {
            operations.push({
                op: 'add',
                path: '/fields/Microsoft.VSTS.Common.Priority',
                value: item.priority
            });
        }
        if (item.state) {
            operations.push({
                op: 'add',
                path: '/fields/System.State',
                value: item.state
            });
        }
        if (item.areaPath) {
            operations.push({
                op: 'add',
                path: '/fields/System.AreaPath',
                value: item.areaPath
            });
        }
        if (item.iterationPath) {
            operations.push({
                op: 'add',
                path: '/fields/System.IterationPath',
                value: item.iterationPath
            });
        }
        if (item.tags && item.tags.length > 0) {
            operations.push({
                op: 'add',
                path: '/fields/System.Tags',
                value: item.tags.join('; ')
            });
        }
        // Add custom fields
        if (item.customFields) {
            Object.entries(item.customFields).forEach(([key, value]) => {
                operations.push({
                    op: 'add',
                    path: `/fields/${key}`,
                    value
                });
            });
        }
        const response = await fetch(url, {
            method: 'POST',
            headers: {
                'Authorization': this.getAuthHeader(),
                'Content-Type': 'application/json-patch+json'
            },
            body: JSON.stringify(operations)
        });
        if (!response.ok) {
            await this.handleErrorResponse(response, `creating ${item.workItemType}`);
        }
        const workItem = await this.safeParseJson(response);
        moduleLogger.info(`✅ Created ${item.workItemType} #${workItem.id}: ${item.title}`);
        // Link to parent if specified
        if (item.parentId) {
            await this.linkWorkItems(workItem.id, item.parentId, 'System.LinkTypes.Hierarchy-Reverse');
        }
        return workItem;
    }
    /**
     * Update an existing work item
     */
    async updateWorkItem(update) {
        moduleLogger.info(`🔧 Updating work item #${update.id}`);
        const url = `${this.baseUrl}/_apis/wit/workitems/${update.id}?api-version=${this.apiVersion}`;
        // Build JSON Patch operations
        const operations = [];
        if (update.title) {
            operations.push({
                op: 'replace',
                path: '/fields/System.Title',
                value: update.title
            });
        }
        if (update.description !== undefined) {
            operations.push({
                op: 'replace',
                path: '/fields/System.Description',
                value: update.description
            });
        }
        if (update.acceptanceCriteria !== undefined) {
            operations.push({
                op: 'replace',
                path: '/fields/Microsoft.VSTS.Common.AcceptanceCriteria',
                value: update.acceptanceCriteria
            });
        }
        if (update.priority !== undefined) {
            operations.push({
                op: 'replace',
                path: '/fields/Microsoft.VSTS.Common.Priority',
                value: update.priority
            });
        }
        if (update.state) {
            operations.push({
                op: 'replace',
                path: '/fields/System.State',
                value: update.state
            });
        }
        if (update.tags) {
            operations.push({
                op: 'replace',
                path: '/fields/System.Tags',
                value: update.tags.join('; ')
            });
        }
        // Add custom fields
        if (update.customFields) {
            Object.entries(update.customFields).forEach(([key, value]) => {
                operations.push({
                    op: 'replace',
                    path: `/fields/${key}`,
                    value
                });
            });
        }
        const response = await fetch(url, {
            method: 'PATCH',
            headers: {
                'Authorization': this.getAuthHeader(),
                'Content-Type': 'application/json-patch+json'
            },
            body: JSON.stringify(operations)
        });
        if (!response.ok) {
            await this.handleErrorResponse(response, `updating work item #${update.id}`);
        }
        const workItem = await this.safeParseJson(response);
        moduleLogger.info(`✅ Updated work item #${update.id}`);
        return workItem;
    }
    /**
     * Link two work items (parent-child relationship)
     */
    async linkWorkItems(childId, parentId, linkType) {
        moduleLogger.info(`🔗 Linking work item #${childId} to parent #${parentId}`);
        const url = `${this.baseUrl}/_apis/wit/workitems/${childId}?api-version=${this.apiVersion}`;
        const operations = [
            {
                op: 'add',
                path: '/relations/-',
                value: {
                    rel: linkType,
                    url: `${this.baseUrl}/_apis/wit/workitems/${parentId}`,
                    attributes: {
                        comment: 'Linked by SpecWeave sync'
                    }
                }
            }
        ];
        const response = await fetch(url, {
            method: 'PATCH',
            headers: {
                'Authorization': this.getAuthHeader(),
                'Content-Type': 'application/json-patch+json'
            },
            body: JSON.stringify(operations)
        });
        if (!response.ok) {
            const error = await response.text();
            if (response.status === 409) {
                moduleLogger.info(`ℹ️  Link already exists between #${childId} and #${parentId} (409)`);
                return;
            }
            throw new Error(`Failed to link work item #${childId} to parent #${parentId}: ${response.status} ${error}`);
        }
        else {
            moduleLogger.info(`✅ Linked work item #${childId} to parent #${parentId}`);
        }
    }
    /**
     * Get current iteration (sprint)
     */
    async getCurrentIteration() {
        const url = `https://dev.azure.com/${this.credentials.organization}/${this.credentials.project}/_apis/work/teamsettings/iterations?$timeframe=current&api-version=${this.apiVersion}`;
        const response = await fetch(url, {
            headers: {
                'Authorization': this.getAuthHeader(),
                'Content-Type': 'application/json'
            }
        });
        if (!response.ok) {
            await this.handleErrorResponse(response, 'fetching current iteration');
        }
        const data = await this.safeParseJson(response);
        const iterations = data.value || [];
        if (iterations.length === 0) {
            moduleLogger.warn('⚠️  No current iteration found');
            return null;
        }
        return iterations[0];
    }
    /**
     * Get all iterations
     */
    async getIterations() {
        const url = `https://dev.azure.com/${this.credentials.organization}/${this.credentials.project}/_apis/work/teamsettings/iterations?api-version=${this.apiVersion}`;
        const response = await fetch(url, {
            headers: {
                'Authorization': this.getAuthHeader(),
                'Content-Type': 'application/json'
            }
        });
        if (!response.ok) {
            await this.handleErrorResponse(response, 'fetching iterations');
        }
        const data = await this.safeParseJson(response);
        return data.value || [];
    }
    /**
     * Get all projects accessible to the user
     */
    async getProjects() {
        const url = `https://dev.azure.com/${this.credentials.organization}/_apis/projects?api-version=${this.apiVersion}`;
        const response = await fetch(url, {
            headers: {
                'Authorization': this.getAuthHeader(),
                'Content-Type': 'application/json'
            }
        });
        if (!response.ok) {
            await this.handleErrorResponse(response, 'fetching projects');
        }
        const data = await this.safeParseJson(response);
        return data.value || [];
    }
    /**
     * Search projects with pagination (for three-tier loading)
     *
     * @param options Search options
     * @returns Paginated project results
     */
    async searchProjects(options = {}) {
        const { top = 50, skip = 0 } = options;
        const url = `https://dev.azure.com/${this.credentials.organization}/_apis/projects?$top=${top}&$skip=${skip}&api-version=${this.apiVersion}`;
        const response = await fetch(url, {
            headers: {
                'Authorization': this.getAuthHeader(),
                'Content-Type': 'application/json'
            }
        });
        if (!response.ok) {
            await this.handleErrorResponse(response, 'searching projects');
        }
        const data = await this.safeParseJson(response);
        return {
            value: data.value || [],
            count: data.count || 0,
        };
    }
    /**
     * Get area paths for a project (classification nodes)
     *
     * @param project Project name or ID
     * @param depth Depth of area path tree (default: 10)
     * @returns Area path tree
     */
    async getAreaPaths(project, depth = 10) {
        const url = `https://dev.azure.com/${this.credentials.organization}/${project}/_apis/wit/classificationnodes/areas?$depth=${depth}&api-version=${this.apiVersion}`;
        const response = await fetch(url, {
            headers: {
                'Authorization': this.getAuthHeader(),
                'Content-Type': 'application/json'
            }
        });
        if (!response.ok) {
            await this.handleErrorResponse(response, `fetching area paths for ${project}`);
        }
        return this.safeParseJson(response);
    }
    /**
     * Get teams for a project
     *
     * @param project Project name or ID
     * @returns Teams array
     */
    async getTeams(project) {
        const url = `https://dev.azure.com/${this.credentials.organization}/_apis/projects/${project}/teams?api-version=${this.apiVersion}`;
        const response = await fetch(url, {
            headers: {
                'Authorization': this.getAuthHeader(),
                'Content-Type': 'application/json'
            }
        });
        if (!response.ok) {
            await this.handleErrorResponse(response, `fetching teams for ${project}`);
        }
        const data = await this.safeParseJson(response);
        return data.value || [];
    }
    /**
     * Fetch recently changed work items for pull sync (Increment 0089)
     *
     * Queries ADO for work items that have changed since a given timestamp.
     * Used by ExternalChangePuller to detect external updates.
     *
     * @param since - Timestamp to query changes from
     * @param linkedItemIds - Optional list of work item IDs to filter (linked items only)
     * @returns Array of external changes with changedAt, changedBy, and current values
     */
    async fetchRecentChanges(since, linkedItemIds) {
        // Build filter for recently changed items
        const filter = {
            changedSince: since,
            top: 100, // Limit to prevent overwhelming results
        };
        // If specific IDs provided, only query those
        if (linkedItemIds && linkedItemIds.length > 0) {
            filter.workItemIds = linkedItemIds;
        }
        // Query work items
        const workItems = await this.listWorkItems(filter);
        // Map to ExternalChange format
        const changes = workItems.map(wi => ({
            platform: 'ado',
            externalId: `ADO-${wi.id}`,
            workItemId: wi.id,
            changedAt: wi.fields['System.ChangedDate'] || new Date().toISOString(),
            changedBy: wi.fields['System.ChangedBy']?.displayName ||
                wi.fields['System.ChangedBy']?.uniqueName ||
                wi.fields['System.ChangedBy'] ||
                'unknown',
            changedFields: [], // ADO doesn't provide field-level changelog in list API
            currentState: {
                status: wi.fields['System.State'] || 'Unknown',
                priority: wi.fields['Microsoft.VSTS.Common.Priority'] ?? null,
                assignee: wi.fields['System.AssignedTo']?.displayName ||
                    wi.fields['System.AssignedTo']?.uniqueName ||
                    wi.fields['System.AssignedTo'] ||
                    null,
            },
        }));
        return changes;
    }
    /**
     * Get work item updates (revision history) for detailed change tracking
     *
     * Use this for detailed changelog when needed.
     * GET /{organization}/{project}/_apis/wit/workitems/{id}/updates
     *
     * @param workItemId - Work item ID
     * @param top - Limit number of updates
     * @returns Array of updates with field changes
     */
    async getWorkItemUpdates(workItemId, top = 10) {
        const url = `${this.baseUrl}/_apis/wit/workitems/${workItemId}/updates?$top=${top}&api-version=${this.apiVersion}`;
        const response = await fetch(url, {
            headers: {
                'Authorization': this.getAuthHeader(),
                'Content-Type': 'application/json'
            }
        });
        if (!response.ok) {
            await this.handleErrorResponse(response, `fetching updates for work item #${workItemId}`);
        }
        const data = await this.safeParseJson(response);
        return data.value || [];
    }
    /**
     * Detect ADO Process Template for the project
     *
     * Uses project properties API to get the process template name,
     * then checks for Capability work item type to detect SAFe/Enterprise.
     *
     * @param project - Optional project name (uses default if not specified)
     * @returns Process template info with hierarchy mapping
     */
    async detectProcessTemplate(project) {
        const projectName = project || this.credentials.project;
        // Step 1: Get project properties (includes process template)
        const projectUrl = `https://dev.azure.com/${this.credentials.organization}/_apis/projects/${projectName}?includeCapabilities=true&api-version=${this.apiVersion}`;
        const projectResponse = await fetch(projectUrl, {
            headers: {
                'Authorization': this.getAuthHeader(),
                'Content-Type': 'application/json'
            }
        });
        if (!projectResponse.ok) {
            await this.handleErrorResponse(projectResponse, `detecting process template for ${projectName}`);
        }
        const projectData = await this.safeParseJson(projectResponse);
        const templateName = projectData.capabilities?.processTemplate?.templateName || 'Agile';
        // Step 2: Get work item types to check for Capability
        const witUrl = `https://dev.azure.com/${this.credentials.organization}/${projectName}/_apis/wit/workitemtypes?api-version=${this.apiVersion}`;
        const witResponse = await fetch(witUrl, {
            headers: {
                'Authorization': this.getAuthHeader(),
                'Content-Type': 'application/json'
            }
        });
        let workItemTypes = [];
        let hasCapability = false;
        if (witResponse.ok) {
            const witData = await this.safeParseJson(witResponse);
            workItemTypes = (witData.value || []).map((wit) => wit.name);
            hasCapability = workItemTypes.some(wit => wit.toLowerCase() === 'capability');
        }
        // Step 3: Determine effective template and hierarchy mapping
        let effectiveTemplate = templateName;
        // If Capability exists, it's SAFe/Enterprise regardless of base template
        if (hasCapability) {
            effectiveTemplate = 'SAFe';
        }
        // Build hierarchy mapping based on template
        const hierarchyMapping = this.buildHierarchyMapping(effectiveTemplate, hasCapability);
        moduleLogger.info(`🔍 Detected ADO Process Template: ${effectiveTemplate}${hasCapability ? ' (with Capability)' : ''}`);
        return {
            template: effectiveTemplate,
            hasCapability,
            workItemTypes,
            hierarchyMapping,
        };
    }
    /**
     * Build hierarchy mapping based on process template
     */
    buildHierarchyMapping(template, hasCapability) {
        // SAFe/Enterprise: Capability → Epic → Feature → US → Task
        // Capability maps to SpecWeave Epic (_epics/EP-XXXE/)
        // Epic maps to SpecWeave Feature (FS-XXXE/)
        if (hasCapability || template === 'SAFe') {
            return {
                capability: 'epic', // ADO Capability → SpecWeave Epic (_epics/EP-XXXE/)
                epic: 'feature', // ADO Epic → SpecWeave Feature (FS-XXXE/)
                feature: 'feature', // ADO Feature → SpecWeave Feature (under Epic's FS-XXXE/)
                userStory: 'user-story',
                task: 'task',
            };
        }
        // Standard templates: Epic → Feature → US → Task
        // Epic maps to SpecWeave Epic (_epics/EP-XXXE/)
        // Feature maps to SpecWeave Feature (FS-XXXE/)
        return {
            epic: 'epic', // ADO Epic → SpecWeave Epic (_epics/EP-XXXE/)
            feature: 'feature', // ADO Feature → SpecWeave Feature (FS-XXXE/)
            userStory: 'user-story',
            task: 'task',
        };
    }
    /**
     * Test connection to Azure DevOps
     */
    async testConnection() {
        try {
            const url = `https://dev.azure.com/${this.credentials.organization}/_apis/projects/${this.credentials.project}?api-version=${this.apiVersion}`;
            const response = await fetch(url, {
                headers: {
                    'Authorization': this.getAuthHeader(),
                    'Content-Type': 'application/json'
                }
            });
            if (response.ok) {
                moduleLogger.info('✅ Azure DevOps connection successful');
                return true;
            }
            else {
                const error = await response.text();
                moduleLogger.error(`❌ Azure DevOps connection failed (${response.status}): ${error}`);
                return false;
            }
        }
        catch (error) {
            moduleLogger.error('❌ Azure DevOps connection failed:', error);
            return false;
        }
    }
    /**
     * Add comment to Azure DevOps work item (T-034C)
     *
     * POST /{organization}/{project}/_apis/wit/workitems/{id}/comments?api-version=7.0
     */
    async addComment(workItemId, comment) {
        const url = `https://dev.azure.com/${this.credentials.organization}/${this.credentials.project}/_apis/wit/workitems/${workItemId}/comments?api-version=${this.apiVersion}`;
        const body = {
            text: comment
        };
        const response = await fetch(url, {
            method: 'POST',
            headers: {
                'Authorization': this.getAuthHeader(),
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(body)
        });
        if (!response.ok) {
            const error = await response.text();
            throw new Error(`Failed to add comment to ADO work item ${workItemId}: ${response.status} ${error}`);
        }
    }
    /**
     * Get last comment on Azure DevOps work item (for idempotency check)
     *
     * GET /{organization}/{project}/_apis/wit/workitems/{id}/comments?$top=1&order=desc&api-version=7.0-preview
     */
    async getLastComment(workItemId) {
        const url = `https://dev.azure.com/${this.credentials.organization}/${this.credentials.project}/_apis/wit/workitems/${workItemId}/comments?%24top=1&order=desc&api-version=${this.apiVersion}-preview`;
        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'Authorization': this.getAuthHeader(),
                'Content-Type': 'application/json'
            }
        });
        if (!response.ok) {
            return null;
        }
        try {
            const data = await response.json();
            if (data.comments && data.comments.length > 0) {
                return { text: data.comments[0].text };
            }
            return null;
        }
        catch {
            return null;
        }
    }
}
/**
   * ADO Process Template types
   */
AdoClient.PROCESS_TEMPLATES = {
    AGILE: 'Agile',
    SCRUM: 'Scrum',
    CMMI: 'CMMI',
    BASIC: 'Basic',
    SAFE: 'SAFe', // Enterprise with Capability work item type
};
//# sourceMappingURL=ado-client.js.map