/**
 * Parse a ValidationIssue's loosely-formatted `amount` and `date` strings into
 * a typed ClarificationExpectation. Returns undefined when the issue carries no
 * structured fields the resolver can act on (e.g. classification-only rules).
 */
const CURRENCY_SYMBOLS = {
    $: 'USD',
    '£': 'GBP',
    '€': 'EUR',
    '¥': 'JPY',
    'A$': 'AUD',
    'AU$': 'AUD',
    'NZ$': 'NZD',
    'C$': 'CAD',
};
const MONTH_NAMES = {
    jan: 0, january: 0,
    feb: 1, february: 1,
    mar: 2, march: 2,
    apr: 3, april: 3,
    may: 4,
    jun: 5, june: 5,
    jul: 6, july: 6,
    aug: 7, august: 7,
    sep: 8, sept: 8, september: 8,
    oct: 9, october: 9,
    nov: 10, november: 10,
    dec: 11, december: 11,
};
/** Pull a numeric amount + currency from strings like "$437.47" or "AU$1,234.50". */
export function parse_amount(raw, default_currency = 'USD') {
    if (raw === undefined || raw === null || raw === '')
        return null;
    if (typeof raw === 'number')
        return { amount: raw, currency: default_currency };
    const trimmed = raw.trim();
    let currency = default_currency;
    let body = trimmed;
    for (const symbol of Object.keys(CURRENCY_SYMBOLS).sort((a, b) => b.length - a.length)) {
        if (body.startsWith(symbol)) {
            currency = CURRENCY_SYMBOLS[symbol];
            body = body.slice(symbol.length);
            break;
        }
    }
    // Repeated symbols ("$$437.47") and stray spaces.
    body = body.replace(/^[\s$£€¥]+/, '').replace(/,/g, '').trim();
    const match = body.match(/-?\d+(?:\.\d+)?/);
    if (!match)
        return null;
    const amount = parseFloat(match[0]);
    if (Number.isNaN(amount))
        return null;
    return { amount, currency };
}
/** Normalise a single date token to YYYY-MM-DD. Accepts ISO, slashed, or "1 July 2024". */
function parse_single_date(token) {
    const trimmed = token.trim();
    if (!trimmed)
        return null;
    if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed))
        return trimmed;
    const slashed = trimmed.match(/^(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2,4})$/);
    if (slashed) {
        const [, d, m, y] = slashed;
        const year = y.length === 2 ? `20${y}` : y;
        return `${year}-${m.padStart(2, '0')}-${d.padStart(2, '0')}`;
    }
    const named = trimmed.match(/^(\d{1,2})\s+([A-Za-z]+)\s+(\d{4})$/);
    if (named) {
        const [, d, mname, y] = named;
        const month_idx = MONTH_NAMES[mname.toLowerCase()];
        if (month_idx !== undefined) {
            return `${y}-${String(month_idx + 1).padStart(2, '0')}-${d.padStart(2, '0')}`;
        }
    }
    return null;
}
/** Parse "1 July 2024 - 30 June 2025" into { from, to }. Single-date input maps to a 1-day range. */
export function parse_date_range(raw) {
    if (!raw)
        return undefined;
    // Require whitespace around the separator so hyphens inside ISO dates aren't split.
    const parts = raw.split(/\s+(?:-|–|—|to)\s+/i);
    if (parts.length === 2) {
        const from = parse_single_date(parts[0]);
        const to = parse_single_date(parts[1]);
        if (from && to)
            return { from, to };
    }
    if (parts.length === 1) {
        const single = parse_single_date(parts[0]);
        if (single)
            return { from: single, to: single };
    }
    return undefined;
}
/**
 * Pull a property address out of an issue description as a fallback when the
 * structured field isn't populated. Looks for "at <addr>", "for <addr>",
 * "property at <addr>", capturing through the next sentence-ending punctuation.
 */
export function parse_property_address(text) {
    if (!text)
        return undefined;
    const match = text.match(/\b(?:for|at)\s+(?:the\s+(?:property|rental)\s+(?:at\s+)?)?([0-9]+[A-Za-z]?\s+[^.,;:\n]{3,80}?)(?=[.,;:\n]|\s+(?:there|with|was|is|are|the|in|and)\b|$)/i);
    return match ? match[1].trim() : undefined;
}
/**
 * Build a ClarificationExpectation from a ValidationIssue. Returns undefined
 * when the issue lacks structured fields (resolver has nothing to check).
 */
export function extract_expectation(issue, options) {
    const default_currency = options?.default_currency ?? 'USD';
    const parsed_amount = parse_amount(issue.amount, default_currency);
    if (!parsed_amount)
        return undefined;
    const date_range = parse_date_range(issue.date);
    // Build context from structured fields first; fall back to parsing the
    // issue description for fields the rule's prompt hasn't been updated to
    // surface yet.
    const property_address = issue.property_address?.trim() ||
        parse_property_address(issue.issue_description);
    const vendor_hint = issue.vendor_hint?.trim();
    const expense_label = issue.expense_label?.trim();
    const context = {};
    if (property_address)
        context.property_address = property_address;
    if (vendor_hint)
        context.vendor_hint = vendor_hint;
    if (expense_label)
        context.expense_label = expense_label;
    return {
        kind: 'sum_match',
        amount: parsed_amount.amount,
        currency: parsed_amount.currency,
        ...(date_range ? { date_range } : {}),
        ...(issue.issue_description ? { description: issue.issue_description } : {}),
        ...(Object.keys(context).length > 0 ? { context } : {}),
    };
}
//# sourceMappingURL=expectation_extractor.js.map