import type Redis from "ioredis";
import type { AttendeeStatus, CalendarEvent } from "@slackwsh/contracts";
import { type EntityIdInput } from "./channels";
export interface CreateEventInput {
    title: string;
    description?: string | null;
    location?: string | null;
    startsAt: string;
    endsAt: string;
    allDay?: boolean;
    timezone?: string;
    recurrenceRule?: string | null;
    channelId?: EntityIdInput | null;
    attendeeUserIds?: EntityIdInput[];
}
export type EventWriteScope = "series" | "occurrence";
export interface UpdateEventInput {
    scope?: EventWriteScope;
    occurrenceDate?: string;
    title?: string;
    description?: string | null;
    location?: string | null;
    startsAt?: string;
    endsAt?: string;
    allDay?: boolean;
    timezone?: string;
    recurrenceRule?: string | null;
    channelId?: EntityIdInput | null;
}
export interface ListEventsFilters {
    from: string;
    to: string;
    channelId?: EntityIdInput;
    mine?: boolean;
}
export declare function createEvent(redis: Redis, workspaceId: EntityIdInput, actorUserId: EntityIdInput, input: CreateEventInput): Promise<CalendarEvent>;
/**
 * Reads a window of the calendar as concrete occurrences.
 *
 * The work is in reconciling three kinds of row against one date range:
 *   - one-off events that overlap the window,
 *   - series (recurrenceRule set) that *might* touch it, expanded on the fly,
 *   - detached children of those series — either an override that replaces one
 *     occurrence, or a cancellation that removes it.
 *
 * Occurrences are never materialised in the database, so this is the only
 * place the three are merged; every client sees the same reconciliation.
 */
export declare function listEvents(workspaceId: EntityIdInput, actorUserId: EntityIdInput, filters: ListEventsFilters): Promise<CalendarEvent[]>;
export declare function getEvent(workspaceId: EntityIdInput, actorUserId: EntityIdInput, eventId: EntityIdInput): Promise<CalendarEvent>;
/**
 * Edits either the whole series or a single occurrence.
 *
 * `scope: "occurrence"` writes a *detached instance*: a child row carrying
 * the merged fields for that one date, which listEvents then substitutes for
 * the expanded occurrence. The series row is untouched, so every other
 * occurrence keeps following the rule. Attendees are copied to the child on
 * first detach, otherwise a moved occurrence would silently lose its invites.
 */
export declare function updateEvent(redis: Redis, workspaceId: EntityIdInput, actorUserId: EntityIdInput, eventId: EntityIdInput, input: UpdateEventInput): Promise<CalendarEvent>;
/**
 * Deletes a whole series (row, its overrides, and all their attendees) or
 * cancels one occurrence.
 *
 * A cancellation is a child row with isCancelled — a tombstone, not an
 * absence. There is nothing to delete for an occurrence that was never
 * materialised, so the row is what tells listEvents to skip it.
 */
export declare function deleteEvent(redis: Redis, workspaceId: EntityIdInput, actorUserId: EntityIdInput, eventId: EntityIdInput, options?: {
    scope?: EventWriteScope;
    occurrenceDate?: string;
}): Promise<void>;
export declare function inviteToEvent(redis: Redis, workspaceId: EntityIdInput, actorUserId: EntityIdInput, eventId: EntityIdInput, attendeeUserIds: EntityIdInput[]): Promise<CalendarEvent>;
/**
 * Answers an invitation. Deliberately takes no target user: you may only RSVP
 * for yourself, which the role table can't express (it has no notion of
 * "subject equals actor"), so it is enforced here by construction rather than
 * by a check that could be forgotten.
 */
export declare function rsvpEvent(redis: Redis, workspaceId: EntityIdInput, actorUserId: EntityIdInput, eventId: EntityIdInput, status: AttendeeStatus): Promise<CalendarEvent>;
//# sourceMappingURL=calendar.d.ts.map