import { ExternalIssueAdapterError, toNormalizedEnvelope, } from './types.js';
import { JiraIssueAdapter } from './adapters.js';
const DEFAULT_JIRA_API_PATH = '/rest/api/3';
const JIRA_ISSUE_FIELDS = [
    'summary',
    'description',
    'labels',
    'priority',
    'status',
    'project',
    'issuetype',
    'assignee',
];
function normalizeBaseUrl(value) {
    const trimmed = value.trim().replace(/\/+$/, '');
    if (/^https?:\/\//i.test(trimmed)) {
        return trimmed;
    }
    return `https://${trimmed}`;
}
function ensureJiraConfig(config) {
    const baseUrl = config.baseUrl
        || config.host
        || process.env.PRLT_JIRA_BASE_URL
        || process.env.JIRA_BASE_URL
        || process.env.PRLT_JIRA_HOST
        || process.env.JIRA_HOST;
    const email = config.email || process.env.PRLT_JIRA_EMAIL || process.env.JIRA_EMAIL || '';
    const apiToken = config.apiToken || process.env.PRLT_JIRA_API_TOKEN || process.env.JIRA_API_TOKEN;
    const projectKey = config.projectKey || process.env.PRLT_JIRA_PROJECT || process.env.JIRA_PROJECT_KEY || '';
    const jql = config.jql || process.env.PRLT_JIRA_JQL || '';
    if (!baseUrl) {
        throw new ExternalIssueAdapterError('MISSING_CONFIG', 'Missing Jira base URL. Set PRLT_JIRA_BASE_URL/JIRA_BASE_URL or PRLT_JIRA_HOST/JIRA_HOST.');
    }
    if (!apiToken) {
        throw new ExternalIssueAdapterError('MISSING_CONFIG', 'Missing Jira API token. Set PRLT_JIRA_API_TOKEN or JIRA_API_TOKEN.');
    }
    return {
        baseUrl: normalizeBaseUrl(baseUrl),
        host: normalizeBaseUrl(baseUrl),
        email,
        apiToken,
        projectKey,
        jql,
    };
}
function ensureIssueKey(key) {
    const trimmed = key.trim().toUpperCase();
    if (!/^[A-Z][A-Z0-9_]*-\d+$/.test(trimmed)) {
        throw new ExternalIssueAdapterError('BAD_PAYLOAD', `Invalid Jira issue key: "${key}".`);
    }
    return trimmed;
}
function buildAuthHeader(config) {
    if (config.email) {
        const token = Buffer.from(`${config.email}:${config.apiToken}`).toString('base64');
        return `Basic ${token}`;
    }
    return `Bearer ${config.apiToken}`;
}
function buildListJql(config, explicitJql) {
    const jql = explicitJql?.trim() || config.jql.trim();
    if (jql.length > 0) {
        return jql;
    }
    const projectKey = config.projectKey.trim();
    if (!projectKey) {
        throw new ExternalIssueAdapterError('MISSING_CONFIG', 'Missing Jira project key/JQL. Pass --project-key or --jql, or set PRLT_JIRA_PROJECT/PRLT_JIRA_JQL.');
    }
    return `project = "${projectKey}" AND statusCategory != Done ORDER BY updated DESC`;
}
function getErrorMessage(payload, fallback) {
    if (!payload || typeof payload !== 'object') {
        return fallback;
    }
    const errorMessages = payload.errorMessages;
    if (Array.isArray(errorMessages) && typeof errorMessages[0] === 'string' && errorMessages[0].trim()) {
        return errorMessages[0].trim();
    }
    return fallback;
}
async function parseJsonOrThrow(response) {
    try {
        return await response.json();
    }
    catch {
        throw new ExternalIssueAdapterError('BAD_PAYLOAD', 'Jira response was not valid JSON.');
    }
}
function deriveJiraCategory(envelope) {
    const typeValue = envelope.item_type?.trim().toLowerCase() || '';
    if (typeValue === 'bug' || typeValue === 'incident') {
        return 'bug';
    }
    if (typeValue === 'task' || typeValue === 'story' || typeValue === 'issue') {
        return 'feature';
    }
    return 'feature';
}
function ensureIssueShape(issue) {
    if (!issue.id || !issue.key || !issue.fields) {
        throw new ExternalIssueAdapterError('BAD_PAYLOAD', 'Jira issue payload is missing required fields (id, key, fields).', issue);
    }
}
export function normalizeJiraIssue(rawIssue) {
    if (!rawIssue || typeof rawIssue !== 'object') {
        throw new ExternalIssueAdapterError('BAD_PAYLOAD', 'Jira issue payload is invalid.', rawIssue);
    }
    const issue = rawIssue;
    ensureIssueShape(issue);
    const adapter = new JiraIssueAdapter();
    return adapter.normalize(issue);
}
export function normalizeJiraIssueToEnvelope(rawIssue) {
    const envelope = normalizeJiraIssue(rawIssue);
    return toNormalizedEnvelope(envelope, deriveJiraCategory(envelope));
}
export function buildJiraTicketDescription(envelope) {
    const body = envelope.description.trim();
    const metadataLines = [
        `- Source: ${envelope.source.name}`,
        `- External key: ${envelope.source.externalKey}`,
        `- External id: ${envelope.source.externalId}`,
        `- URL: ${envelope.source.url}`,
        `- Status: ${envelope.status}`,
        `- Priority: ${envelope.priority || 'Unset'}`,
        `- Labels: ${envelope.labels.length > 0 ? envelope.labels.join(', ') : 'None'}`,
    ];
    const parts = [
        body,
        '## External Issue Context',
        metadataLines.join('\n'),
    ].filter(Boolean);
    return parts.join('\n\n');
}
export function buildJiraMetadata(envelope) {
    return {
        external_source: envelope.source.name,
        external_key: envelope.source.externalKey,
        external_id: envelope.source.externalId,
        external_url: envelope.source.url,
        external_raw: JSON.stringify(envelope.source.raw),
    };
}
export function buildJiraSpawnContextMessage(envelope, additionalMessage) {
    const lines = [
        `External issue source: ${envelope.source.name}`,
        `External issue key: ${envelope.source.externalKey}`,
        `External issue id: ${envelope.source.externalId}`,
        `External issue URL: ${envelope.source.url}`,
    ];
    if (additionalMessage?.trim()) {
        lines.push('', additionalMessage.trim());
    }
    return lines.join('\n');
}
export function buildJiraIssueChoiceCommand(issueKey, projectId) {
    let command = `prlt work jira --issue ${issueKey} --json`;
    if (projectId) {
        command += ` -P ${projectId}`;
    }
    return command;
}
export async function getJiraIssueByKey(configInput, issueKey, options) {
    const config = ensureJiraConfig(configInput);
    const fetchImpl = options?.fetchImpl || fetch;
    const key = ensureIssueKey(issueKey);
    const baseApiUrl = `${config.baseUrl}${DEFAULT_JIRA_API_PATH}`;
    const fields = encodeURIComponent(JIRA_ISSUE_FIELDS.join(','));
    const issueUrl = `${baseApiUrl}/issue/${encodeURIComponent(key)}?fields=${fields}`;
    const response = await fetchImpl(issueUrl, {
        method: 'GET',
        headers: {
            Accept: 'application/json',
            Authorization: buildAuthHeader(config),
        },
    });
    if (response.status === 401 || response.status === 403) {
        throw new ExternalIssueAdapterError('AUTH_FAILED', 'Jira authentication failed. Verify your Jira credentials.');
    }
    if (response.status === 404) {
        return null;
    }
    const payload = await parseJsonOrThrow(response);
    if (!response.ok) {
        const msg = getErrorMessage(payload, `Jira request failed with status ${response.status}.`);
        throw new ExternalIssueAdapterError('REQUEST_FAILED', msg, payload);
    }
    return normalizeJiraIssueToEnvelope(payload);
}
export async function listJiraIssues(configInput, options) {
    const config = ensureJiraConfig(configInput);
    const fetchImpl = options?.fetchImpl || fetch;
    const limit = Math.max(1, Math.min(options?.limit ?? 20, 100));
    const jql = buildListJql(config, options?.jql);
    const baseApiUrl = `${config.baseUrl}${DEFAULT_JIRA_API_PATH}`;
    const response = await fetchImpl(`${baseApiUrl}/search`, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            Accept: 'application/json',
            Authorization: buildAuthHeader(config),
        },
        body: JSON.stringify({
            jql,
            maxResults: limit,
            fields: JIRA_ISSUE_FIELDS,
        }),
    });
    if (response.status === 401 || response.status === 403) {
        throw new ExternalIssueAdapterError('AUTH_FAILED', 'Jira authentication failed. Verify your Jira credentials.');
    }
    const payload = await parseJsonOrThrow(response);
    if (!response.ok) {
        const msg = getErrorMessage(payload, `Jira request failed with status ${response.status}.`);
        throw new ExternalIssueAdapterError('REQUEST_FAILED', msg, payload);
    }
    const data = payload;
    if (!Array.isArray(data.issues)) {
        throw new ExternalIssueAdapterError('BAD_PAYLOAD', 'Jira response payload was missing issues array.', payload);
    }
    return data.issues.map(normalizeJiraIssueToEnvelope);
}
//# sourceMappingURL=jira.js.map