import { ResolvedFilter, DetectionConfig } from './detection-config.schema.js';
import { IChangeSource, IntegrationSubscriptionView, Change } from './integration-change-source.protocol.js';
import { ChangeMiddleware } from './integration-middleware.protocol.js';
import 'zod';

/**
 * Integration subsystem — `PollChangeSource<T>` primitive (#226-3, ADR-033).
 *
 * Generic poll-mode `IChangeSource<T>` implementation parameterized by a
 * parsed `DetectionConfig` (poll mode) and a consumer-supplied
 * `PollFetchCallback<T>`. The primitive owns:
 *
 *   - filter resolution (flat-AND vocabulary per epic decision Q3 — richer
 *     boolean expressions deferred);
 *   - field mapping → `Change.externalId` derivation;
 *   - cursor strategy passthrough (the orchestrator passes the prior cursor
 *     by-value per ADR-033 / #226-2; the callback yields the next cursor
 *     per record; the primitive simply stamps it onto `Change<T>`);
 *   - `Change<T>.source` provenance (`'poll'` by default);
 *   - middleware-chain composition (the `ChangeMiddleware<T>` shape
 *     locked in #226-1).
 *
 * Shape locks (decision memo Q5):
 *   - `PollFetchContext = { subscription, cursor, filters }` — explicitly
 *     NO `userId` / `tenantId`. Run-scope identity is closed over by the
 *     consumer at adapter construction (or resolved inside the callback
 *     via consumer services). Threading it through the seam would force
 *     port expansion every time run-context grows.
 *
 * The adapter callback returns `{ record: T; cursor: PollCursor }` — the
 * primitive does not reach into the record to extract a cursor itself.
 * `cursor.field` from `DetectionConfig.poll.cursor` is metadata for codegen
 * + adapters; the primitive trusts what the callback yielded.
 */

/**
 * Opaque poll-cursor shape. Each provider/entity pair binds it concretely
 * via the cursor strategy (`{ systemModstamp }`, `{ replayId }`, etc.); the
 * primitive treats it as an opaque value to pass through.
 */
type PollCursor = unknown;
/**
 * The context the primitive forwards to the adapter callback. Locked to
 * exactly three fields per decision memo Q5 — `userId` / `tenantId` are
 * NOT here on purpose.
 */
interface PollFetchContext {
    readonly subscription: IntegrationSubscriptionView;
    readonly cursor: PollCursor | null;
    readonly filters: readonly ResolvedFilter[];
}
/**
 * Consumer-supplied fetch callback. Returns an async iterable of
 * `{ record, cursor }` pairs — `record` is already the canonical `T`
 * (the adapter does provider-side translation), `cursor` is the post-record
 * cursor the orchestrator should persist if the run completes successfully.
 */
type PollFetchCallback<T> = (ctx: PollFetchContext) => AsyncIterable<{
    record: T;
    cursor: PollCursor;
}>;
interface PollChangeSourceOptions<T> {
    /** Consumer-supplied fetch callback. */
    readonly adapter: PollFetchCallback<T>;
    /**
     * Parsed detection config. MUST be `mode: 'poll'`; the constructor
     * throws if a webhook config is supplied. Codegen-emitted factories
     * call `DetectionConfigSchema.parse(...)` upstream so this is a safety
     * net, not the primary validation point.
     */
    readonly config: DetectionConfig;
    /**
     * Optional middleware chain. First element is the outermost layer:
     * sees `(subscription, cursor)` first and yielded `Change<T>` last.
     * Locked shape (#226-1) — the primitive composes them with its own
     * `listChanges` implementation as the innermost iterator.
     */
    readonly middlewares?: ReadonlyArray<ChangeMiddleware<T>>;
    /**
     * Optional human label for run logs (e.g. `'salesforce-poll-opportunity'`).
     * Defaults to a derived label based on the subscription domain at
     * construction time fallback — adapters are encouraged to provide one.
     */
    readonly label?: string;
}
declare class PollChangeSource<T> implements IChangeSource<T> {
    readonly label: string;
    private readonly adapter;
    private readonly filters;
    private readonly externalIdSourceField;
    private readonly source;
    /**
     * When `poll.provenance === 'cdc'`, the field on the emitted record from
     * which `Change<T>.dedupKey` is read — sourced from `poll.cursor.field`
     * (Stripe-style event endpoints carry the event id on the record itself
     * and the cursor advances over the same id). `null` for default poll
     * provenance, which does NOT populate `dedupKey`.
     */
    private readonly dedupKeySourceField;
    private readonly composed;
    constructor(opts: PollChangeSourceOptions<T>);
    listChanges(subscription: IntegrationSubscriptionView, cursor: unknown | null): AsyncIterable<Change<T>>;
    private fetch;
}

export { PollChangeSource, type PollChangeSourceOptions, type PollCursor, type PollFetchCallback, type PollFetchContext };
