/// <reference lib="esnext.temporal" />
import { Activity } from "@fedify/vocab";
import { Context, Federation, InboxContext, OutboxContext, RequestContext } from "@fedify/fedify/federation";
import { MessageQueue } from "@fedify/fedify";

//#region src/context.d.ts
declare function createContext<TContextData>(values: Partial<Context<TContextData>> & {
  url?: URL;
  data: TContextData;
  federation: Federation<TContextData>;
}): Context<TContextData>;
/**
* Creates a RequestContext for testing purposes.
* Not exported - used internally only. Public API is in mock.ts
* @param args Partial RequestContext properties
* @returns A RequestContext instance
* @since 1.8.0
*/
declare function createRequestContext<TContextData>(args: Partial<RequestContext<TContextData>> & {
  url: URL;
  data: TContextData;
  federation: Federation<TContextData>;
}): RequestContext<TContextData>;
/**
* Test-specific InboxContext type alias.
* This indirection helps avoid JSR type analyzer issues.
* @since 1.9.1
*/
type TestInboxContext<TContextData> = InboxContext<TContextData>;
/**
* Test-specific OutboxContext type alias.
* This indirection helps avoid JSR type analyzer issues.
* @since 2.2.0
*/
type TestOutboxContext<TContextData> = OutboxContext<TContextData>;
/**
* Creates an InboxContext for testing purposes.
* Not exported - used internally only. Public API is in mock.ts
* @param args Partial InboxContext properties
* @returns An InboxContext instance
* @since 1.8.0
*/
declare function createInboxContext<TContextData>(args: Partial<InboxContext<TContextData>> & {
  url?: URL;
  data: TContextData;
  recipient?: string | null;
  federation: Federation<TContextData>;
}): TestInboxContext<TContextData>;
/**
* Creates an OutboxContext for testing purposes.
* Not exported - used internally only. Public API is in mock.ts
* @param args Partial OutboxContext properties
* @returns An OutboxContext instance
* @since 2.2.0
*/
declare function createOutboxContext<TContextData>(args: Partial<OutboxContext<TContextData>> & {
  url?: URL;
  data: TContextData;
  identifier: string;
  federation: Federation<TContextData>;
}): TestOutboxContext<TContextData>;
//#endregion
//#region src/mock.d.ts
/**
* Represents a sent activity with metadata about how it was sent.
* @since 1.8.0
*/
interface SentActivity {
  /** Whether the activity was queued or sent immediately. */
  queued: boolean;
  /** Which queue was used (if queued). */
  queue?: "inbox" | "outbox" | "fanout";
  /** The activity that was sent. */
  activity: Activity;
  /** The raw forwarded payload, if preserved by the caller. */
  rawActivity?: unknown;
  /** The order in which the activity was sent (auto-incrementing counter). */
  sentOrder: number;
}
/**
* A mock Context interface for testing purposes.
* Extends the standard Context interface with additional testing utilities.
* @since 1.9.1
*/
interface TestContext<TContextData> extends Omit<Context<TContextData>, "clone">, Pick<RequestContext<TContextData>, "request" | "url" | "getActor" | "getObject" | "getSignedKey" | "getSignedKeyOwner" | "sendActivity" | "routeActivity"> {
  clone(data: TContextData): TestContext<TContextData>;
  getSentActivities(): Array<{
    sender: any;
    recipients: any;
    activity: Activity;
    rawActivity?: unknown;
  }>;
  reset(): void;
}
/**
* A mock Federation interface for testing purposes.
* Extends the standard Federation interface with additional testing utilities.
* @since 1.9.1
*/
interface TestFederation<TContextData> extends Omit<Federation<TContextData>, "createContext"> {
  sentActivities: SentActivity[];
  queueStarted: boolean;
  sentCounter: number;
  receiveActivity(activity: Activity): Promise<void>;
  postOutboxActivity(identifier: string, activity: Activity): Promise<void>;
  reset(): void;
  createContext(baseUrlOrRequest: URL | Request, contextData: TContextData): TestContext<TContextData>;
}
/**
* Creates a mock Federation instance for testing purposes.
*
* @template TContextData The type of context data to use
* @param options Optional configuration for the mock federation
* @returns A Federation instance that can be used for testing
* @since 1.9.1
*
* @example
* ```typescript
* import { Create } from "@fedify/vocab";
* import { createFederation } from "@fedify/testing";
*
* // Create a mock federation with contextData
* const federation = createFederation<{ userId: string }>({
*   contextData: { userId: "test-user" }
* });
*
* // Set up inbox listeners
* federation
*   .setInboxListeners("/users/{identifier}/inbox")
*   .on(Create, async (ctx, activity) => {
*     console.log("Received:", activity);
*   });
*
* // Simulate receiving an activity
* const createActivity = new Create({
*   id: new URL("https://example.com/create/1"),
*   actor: new URL("https://example.com/users/alice")
* });
* await federation.receiveActivity(createActivity);
*
* // Check sent activities
* console.log(federation.sentActivities);
* ```
*/
declare function createFederation<TContextData>(options?: {
  contextData?: TContextData;
  origin?: string;
  tracerProvider?: any;
}): TestFederation<TContextData>;
//#endregion
//#region src/mq-tester.d.ts
/**
* Options for {@link testMessageQueue}.
*/
interface TestMessageQueueOptions {
  /**
  * Whether to test ordering key support.  If `true`, tests will verify that
  * messages with the same ordering key are processed in order, while messages
  * with different ordering keys can be processed in parallel.
  *
  * Set this to `true` only if your message queue implementation supports
  * the `orderingKey` option.
  *
  * @default false
  */
  readonly testOrderingKey?: boolean;
}
/**
* Tests a {@link MessageQueue} implementation with a standard set of tests.
*
* This function runs tests for:
* - `enqueue()`: Basic message enqueueing
* - `enqueue()` with delay: Delayed message enqueueing
* - `enqueueMany()`: Bulk message enqueueing
* - `enqueueMany()` with delay: Delayed bulk message enqueueing
* - Multiple listeners: Ensures messages are processed by only one listener
* - Ordering key support (optional): Ensures messages with the same ordering
*   key are processed in order
*
* @example
* ```typescript ignore
* import { test } from "@fedify/fixture";
* import { testMessageQueue } from "@fedify/testing";
* import { MyMessageQueue } from "./my-mq.ts";
*
* test("MyMessageQueue", () =>
*   testMessageQueue(
*     () => new MyMessageQueue(),
*     async ({ mq1, mq2, controller }) => {
*       controller.abort();
*       await mq1.close();
*       await mq2.close();
*     },
*     { testOrderingKey: true },  // Enable ordering key tests
*   )
* );
* ```
*
* @param getMessageQueue A factory function that creates a new message queue
*                        instance.  It should return a new instance each time
*                        to ensure test isolation, but both instances should
*                        share the same underlying storage/channel.
* @param onFinally A cleanup function called after all tests complete.
*                  It receives both message queue instances and the abort
*                  controller used for the listeners.
* @param options Optional configuration for the test suite.
* @returns A promise that resolves when all tests pass.
*/
declare function testMessageQueue<MQ extends MessageQueue>(getMessageQueue: () => MQ | Promise<MQ>, onFinally: ({
  mq1,
  mq2,
  controller
}: {
  mq1: MQ;
  mq2: MQ;
  controller: AbortController;
}) => Promise<void> | void, options?: TestMessageQueueOptions): Promise<void>;
declare function waitFor(predicate: () => boolean, timeoutMs: number): Promise<void>;
declare const getRandomKey: (prefix: string) => string;
//#endregion
export { type TestMessageQueueOptions, createContext, createFederation, createInboxContext, createOutboxContext, createRequestContext, getRandomKey, testMessageQueue, waitFor };