import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
import { ServiceFactory, LoggerService, BackstageCredentials } from '@backstage/backend-plugin-api';
import { JsonObject, JsonValue } from '@backstage/types';
import { AnyZodObject } from 'zod';
import { ActionsRegistryService, ActionsService, ActionsRegistryActionOptions, ActionsServiceAction } from '@backstage/backend-plugin-api/alpha';

/** @alpha */
type ServiceMock<TService> = {
    factory: ServiceFactory<TService>;
} & {
    [Key in keyof TService]: TService[Key] extends (...args: infer Args) => infer Return ? TService[Key] & jest.MockInstance<Return, Args> : TService[Key];
};

/**
 * A mock implementation of the ActionsRegistryService and ActionsService that can be used in tests.
 *
 * This is useful for testing actions that are registered with the ActionsRegistryService and ActionsService.
 *
 * The plugin ID is hardcoded to `testing` in the mock implementation.
 *
 * @example
 * ```ts
 * const actionsRegistry = mockServices.actionsRegistry();
 *
 * actionsRegistry.register({
 *   name: 'test',
 *   title: 'Test',
 *   description: 'Test',
 *   schema: {
 *     input: z.object({ name: z.string() }),
 *     output: z.object({ name: z.string() }),
 *   },
 *   action: async ({ input }) => ({ output: { name: input.name } }),
 * });
 *
 *
 * const result = await actionsRegistry.invoke({
 *   id: 'testing:test',
 *   input: { name: 'test' },
 * });
 *
 * expect(result).toEqual({ output: { name: 'test' } });
 * ```
 *
 * @alpha
 */
declare class MockActionsRegistry implements ActionsRegistryService, ActionsService {
    private readonly logger;
    private constructor();
    static create(opts: {
        logger: LoggerService;
    }): MockActionsRegistry;
    readonly actions: Map<string, ActionsRegistryActionOptions<any, any>>;
    list(): Promise<{
        actions: ActionsServiceAction[];
    }>;
    invoke(opts: {
        id: string;
        input?: JsonObject;
        credentials?: BackstageCredentials;
    }): Promise<{
        output: JsonValue;
    }>;
    register<TInputSchema extends AnyZodObject, TOutputSchema extends AnyZodObject>(options: ActionsRegistryActionOptions<TInputSchema, TOutputSchema>): void;
}

/**
 * @alpha
 */
declare function actionsRegistryServiceMock(options?: {
    logger: LoggerService;
}): MockActionsRegistry;
/**
 * @alpha
 */
declare namespace actionsRegistryServiceMock {
    const factory: () => _backstage_backend_plugin_api.ServiceFactory<ActionsRegistryService, "plugin", "singleton">;
    const mock: (partialImpl?: Partial<ActionsRegistryService> | undefined) => ServiceMock<ActionsRegistryService>;
}

/**
 * @alpha
 */
declare namespace actionsServiceMock {
    const factory: () => _backstage_backend_plugin_api.ServiceFactory<ActionsService, "plugin", "singleton">;
    const mock: (partialImpl?: Partial<ActionsService> | undefined) => ServiceMock<ActionsService>;
}

export { MockActionsRegistry, type ServiceMock, actionsRegistryServiceMock, actionsServiceMock };
