import { DateTime } from 'luxon';
/** True when d is a valid calendar day-of-month for O&M (1–31). */
export declare function isValidOmDayOfMonth(d: unknown): d is number;
/**
 * Earliest calendar date **strictly after** `calendarToday` (same zone) whose day-of-month is the scheme’s
 * recurring O&M day, clamped to each month’s length (e.g. O&M 31 → Feb 28/29). Used so scheduled invoices
 * run only when **tomorrow** equals this next occurrence, not a coincidental day-of-month match.
 */
export declare function resolveNextOmOccurrenceStrictlyAfter(calendarToday: DateTime, omDay: number): DateTime | null;
/**
 * O&M bill period for the line item, from O&M day-of-month and targetDate (today+1 in scheduler TZ).
 * See plan: periodFrom = omDay on (T − 1 month, clamped); periodTo = omDay−1 on T, or last day of prev month if omDay === 1.
 */
export type OmBillPeriodResult = {
    periodFrom: DateTime;
    periodTo: DateTime;
    daysInclusive: number;
    periodFromDisplay: string;
    periodToDisplay: string;
    omBillDateLine: string;
};
export declare function computeOmBillPeriod(omDay: number, targetDate: DateTime): OmBillPeriodResult;
/**
 * Ensures no billed window lies entirely **before** O&M service starts.
 * Raw {@link computeOmBillPeriod} can produce a window ending the day **before**
 * {@code om_start_date} on the **first** billing cycle (tomorrow === first O&M day).
 *
 * When the raw window ends before `om_start_date`, replaces it with:
 * **[om_start, next recurring O&M day strictly after start) − 1 calendar day]** (one service month).
 * When only `period_from` precedes service start but `period_to` does not, clips `period_from` upward.
 */
export declare function clampOmBillPeriodToOmStart(bill: OmBillPeriodResult, omStartDate: unknown, timeZone: string): OmBillPeriodResult;
/**
 * Parse YYYY-MM-DD date-only strings as UTC midnight. For full ISO datetimes use
 * {@link resolveOmDayFromSchemeOmStartDate} with a scheduler timezone.
 */
export declare function parseOmDayFromIsoDate(omStartDate: string | undefined | null): number | null;
/**
 * Safe O&M calendar day from scheme.om_start_date (invalid / unparsable → null; never NaN).
 * Pass the same timezone as `INVOICE_SCHEDULER_TIMEZONE` (and ideally PostgreSQL TimeZone for `::date`).
 */
export declare function resolveOmDayFromSchemeOmStartDate(omStartDate: unknown, schedulerTimezone?: string): number | null;
/**
 * Number of completed monthly O&M billing cycles between `om_start_date` and `asOf`,
 * using the **same anchor + clamp logic the catch-up worker uses**
 * (`buildCompletedCatchupAnchorWindows` in `newSchemeInvoiceCatchup.service.ts`).
 *
 * Each completed cycle = one invoice the catch-up worker can/will create. Used to cap
 * `paid_invoice_count` on scheme create / import so the user cannot mark more invoices
 * as already-paid than there are billing cycles available to backfill.
 *
 * Counting rule (matches the worker):
 *   - The next anchor strictly after `om_start_date` is the 1st cycle's `targetDate`.
 *   - That cycle is "completed" only when its clamped billing period's `periodTo` is
 *     on or before `asOf` (i.e. the full month has elapsed in the scheduler timezone).
 *   - Hard cap of 240 iterations protects against runaway loops.
 *
 * Example: om_start = 2026-02-12, asOf = 2026-05-10 (Asia/Kolkata) → returns 2
 * (cycles for 2026-03-12 and 2026-04-12 have completed; 2026-05-12 has not).
 */
export declare function countCompletedOmBillingCycles(omStartIso: string, asOf: DateTime, timezone: string): number;
/** Debug fields for logs when diagnosing om_start_date parsing vs SQL eligibility. */
export declare function getOmStartDateDebugInfo(omStartDate: unknown, schedulerTimezone: string): Record<string, string | number | boolean | null | undefined>;
//# sourceMappingURL=omBillingPeriod.d.ts.map