/**
 * Locale-aware time formatting for scheduling tool output.
 *
 * All functions are pure — no side effects, no database access.
 * Timezone is always required (IANA format). No defaults, no fallbacks.
 *
 * DATA FLOW:
 *   Neo4j (UTC ISO) --> formatCombined(iso, tz) --> MCP tool response
 *                                │
 *                        ┌───────┴───────┐
 *                        v               v
 *               formatLocaleTime   formatRelativeDelta
 *               (Intl.DateTimeFormat)  (ms arithmetic)
 */
// ---------------------------------------------------------------------------
// Timezone validation
// ---------------------------------------------------------------------------
/**
 * Validates an IANA timezone string. Throws with a clear message if invalid.
 */
export function validateTimezone(tz) {
    if (!tz || tz.trim().length === 0) {
        throw new Error("Timezone is required but was empty");
    }
    try {
        // Intl.DateTimeFormat throws RangeError for invalid IANA timezone identifiers
        new Intl.DateTimeFormat("en-GB", { timeZone: tz });
    }
    catch {
        throw new Error(`Invalid timezone: "${tz}" — expected IANA format like "Europe/London" or "America/New_York"`);
    }
}
// ---------------------------------------------------------------------------
// Locale formatting
// ---------------------------------------------------------------------------
/**
 * Formats a UTC ISO 8601 string into a human-readable locale string.
 *
 * Example: "2026-04-03T11:00:00.000Z" + "Europe/London"
 *       → "Thursday 3 April 2026, 12:00 BST"
 */
export function formatLocaleTime(isoString, timezone) {
    validateTimezone(timezone);
    const date = new Date(isoString);
    if (isNaN(date.getTime())) {
        throw new Error(`Invalid ISO date string: "${isoString}"`);
    }
    // Full date with day name, time, and timezone abbreviation
    const formatted = new Intl.DateTimeFormat("en-GB", {
        weekday: "long",
        day: "numeric",
        month: "long",
        year: "numeric",
        hour: "2-digit",
        minute: "2-digit",
        timeZone: timezone,
        timeZoneName: "short",
    }).format(date);
    return formatted;
}
// ---------------------------------------------------------------------------
// Relative delta
// ---------------------------------------------------------------------------
// Cutoffs for relative time display:
//   < 1 min:    "just now" / "in less than a minute"
//   1-59 min:   "X minutes ago" / "in X minutes"
//   1-23 hours: "X hours ago" / "in X hours"
//   1-6 days:   "X days ago" / "in X days"
//   7+ days:    null (no relative — locale date alone is sufficient)
const MINUTE_MS = 60_000;
const HOUR_MS = 3_600_000;
const DAY_MS = 86_400_000;
/**
 * Computes a human-readable relative time delta.
 *
 * Returns null for dates more than 6 days away (relative deltas
 * become less useful at that distance).
 *
 * @param isoString - UTC ISO 8601 timestamp
 * @param now       - Current time (injectable for testing)
 */
export function formatRelativeDelta(isoString, now = new Date()) {
    const target = new Date(isoString);
    if (isNaN(target.getTime())) {
        throw new Error(`Invalid ISO date string: "${isoString}"`);
    }
    const diffMs = target.getTime() - now.getTime();
    const absDiffMs = Math.abs(diffMs);
    const isFuture = diffMs > 0;
    // 7+ days → no relative delta
    if (absDiffMs >= 7 * DAY_MS) {
        return null;
    }
    // < 1 minute
    if (absDiffMs < MINUTE_MS) {
        return isFuture ? "in less than a minute" : "just now";
    }
    // Minutes (1-59)
    if (absDiffMs < HOUR_MS) {
        const minutes = Math.floor(absDiffMs / MINUTE_MS);
        const unit = minutes === 1 ? "minute" : "minutes";
        return isFuture ? `in ${minutes} ${unit}` : `${minutes} ${unit} ago`;
    }
    // Hours (1-23)
    if (absDiffMs < DAY_MS) {
        const hours = Math.floor(absDiffMs / HOUR_MS);
        const unit = hours === 1 ? "hour" : "hours";
        return isFuture ? `in ${hours} ${unit}` : `${hours} ${unit} ago`;
    }
    // Days (1-6)
    const days = Math.floor(absDiffMs / DAY_MS);
    if (days === 1) {
        return isFuture ? "tomorrow" : "yesterday";
    }
    const unit = "days";
    return isFuture ? `in ${days} ${unit}` : `${days} ${unit} ago`;
}
// ---------------------------------------------------------------------------
// Combined format
// ---------------------------------------------------------------------------
/**
 * Produces the full locale-formatted string with optional relative delta.
 *
 * Examples:
 *   "Thursday 3 April 2026, 12:00 BST (in 51 minutes)"
 *   "Friday 10 April 2026, 09:00 BST"  (no relative — 7+ days away)
 *
 * @param isoString - UTC ISO 8601 timestamp
 * @param timezone  - IANA timezone identifier
 * @param now       - Current time (injectable for testing)
 */
export function formatCombined(isoString, timezone, now = new Date()) {
    const locale = formatLocaleTime(isoString, timezone);
    const relative = formatRelativeDelta(isoString, now);
    if (relative) {
        return `${locale} (${relative})`;
    }
    return locale;
}
//# sourceMappingURL=time-format.js.map