import type { IdentifierMetadata } from '@suites/types.di';
import type { DeepPartial, Type } from '@suites/types.common';
import type { ArgsType, Stub, StubbedInstance } from '@suites/types.doubles';
import type { SociableTestBedBuilder as SociableTestBedBuilderCore, TestBedBuilder as TestBedBuilderCore, UnitReference as UnitReferenceCore, MockOverride as MockOverrideCore } from '@suites/core.unit';
/**
 * Represents a test double instance where all methods and properties are stubbed.
 *
 * This abstract type provides the foundation for creating test doubles in unit tests.
 * When a testing adapter is installed, this type is automatically augmented with
 * framework-specific capabilities through TypeScript module augmentation.
 *
 * @template T The type of the object being transformed into a test double
 *
 * @remarks
 * This is a base abstraction that adapters enhance with concrete implementations.
 * The actual runtime behavior depends on which testing adapter is installed.
 *
 * @since 3.0.0
 * @see {@link https://suites.dev/docs/api-reference/types | Type Reference}
 */
export type Mocked<T> = StubbedInstance<T>;
export interface SociableTestBedBuilder<TClass> extends SociableTestBedBuilderCore<TClass> {
    /**
     * Exposes a dependency to be included in the test environment in its real or partially mocked state.
     * This method is used to selectively expose dependencies that should not be fully mocked.
     * It allows for sociable testing, where the class under test interacts with real implementations
     * or partial mocks of certain dependencies.
     *
     * @since 3.0.0
     * @template TClass The type of the class under test.
     * @param dependency - The dependency to be exposed in its real or partially mocked state.
     * @returns A TestBedBuilder instance for further configuration.
     * @example
     * ```ts
     * import { TestBed } from '@suites/unit';
     * import { MyService, AnotherService } from './my-service.js';
     *
     * const { unit, unitRef } = await TestBed.sociable(MyService).expose(AnotherService).compile();
     * // MyService is now tested with AnotherService exposed and not fully mocked.
     * ```
     * @see {@link https://suites.dev/docs/api-reference/testbed-sociable | TestBed.sociable() API Reference}
     */
    expose(dependency: Type): SociableTestBedBuilder<TClass>;
}
export interface SolitaryTestBedBuilder<TClass> extends TestBedBuilder<TClass> {
}
/**
 * Provides access to mocked dependencies in the test environment.
 *
 * The `unitRef` allows you to retrieve mocked instances of dependencies
 * to configure their behavior or verify interactions. This is essential for
 * controlling how mocked dependencies respond during tests.
 *
 * The return type of `.get()` is augmented by adapter packages to provide
 * framework-specific mock types. Configure augmentation by referencing the
 * adapter's unit.d.ts in your global.d.ts.
 *
 * @since 3.0.0
 * @see {@link https://suites.dev/docs/api-reference/unit-reference | UnitReference API Reference}
 *
 * @example
 * ```ts
 * import { TestBed } from '@suites/unit';
 *
 * const { unit, unitRef } = await TestBed.solitary(MyService).compile();
 *
 * // Get a mocked dependency
 * const mockLogger = unitRef.get(Logger);
 * mockLogger.log.mockReturnValue('test');
 *
 * // Verify interactions
 * unit.doSomething();
 * expect(mockLogger.log).toHaveBeenCalled();
 * ```
 */
export interface UnitReference extends UnitReferenceCore {
    /**
     * Retrieves a reference to the mocked object of a dependency corresponding to its type identifier.
     *
     * @since 3.0.0
     * @template TDependency The type of the dependency being retrieved.
     * @param type - The type representing the dependency.
     * @throws {@link DependencyResolutionError} If the dependency is not found.
     * @returns The mocked object corresponding to the provided type identifier.
     */
    get<TDependency>(type: Type<TDependency>): StubbedInstance<TDependency>;
    /**
     * Retrieves a reference to the mocked object of a dependency corresponding to its type identifier
     * and metadata object.
     *
     * @since 3.0.0
     * @template TDependency The type of the dependency being retrieved.
     * @param type - The type representing the dependency.
     * @param identifierMetadata - A metadata object that corresponds to the type identifier.
     * @throws {@link DependencyResolutionError} If the dependency is not found.
     * @returns The mocked object corresponding to the provided
     * symbol-based token.
     */
    get<TDependency>(type: Type<TDependency>, identifierMetadata: IdentifierMetadata): StubbedInstance<TDependency>;
    /**
     * Retrieves a reference to the mocked object of a dependency corresponding to a string-based token.
     *
     * @since 3.0.0
     * @template TDependency The type of the dependency being retrieved.
     * @param token - The string-based token representing the dependency.
     * @throws {@link DependencyResolutionError} If the dependency is not found.
     * @returns The mocked object corresponding to the provided string-based token.
     */
    get<TDependency>(token: string): StubbedInstance<TDependency>;
    /**
     * Retrieves a reference to the mocked object of a dependency corresponding to a string-based
     * token and an identifier metadata object.
     *
     * @since 3.0.0
     * @template TDependency The type of the dependency being retrieved.
     * @param token - The symbol-based token representing the dependency.
     * @param identifierMetadata - An accompanying metadata object for the token identifier.
     * @throws {@link DependencyResolutionError} If the dependency is not found.
     * @returns The mocked object corresponding to the provided
     * symbol-based token.
     */
    get<TDependency>(token: string, identifierMetadata: IdentifierMetadata): StubbedInstance<TDependency>;
    /**
     * Retrieves a reference to the mocked object of a dependency corresponding to a symbol-based token.
     *
     * @since 3.0.0
     * @template TDependency The type of the dependency being retrieved.
     * @param token - The symbol-based token representing the dependency.
     * @throws {@link DependencyResolutionError} If the dependency is not found.
     * @returns The mocked object corresponding to the provided symbol-based token.
     */
    get<TDependency>(token: symbol): StubbedInstance<TDependency>;
    /**
     * Retrieves a reference to the mocked object of a dependency corresponding to a symbol-based
     * token and an identifier metadata object.
     *
     * @since 3.0.0
     * @template TDependency The type of the dependency being retrieved.
     * @param token - The symbol-based token representing the dependency.
     * @param identifierMetadata - An accompanying metadata object for the token identifier.
     * @throws {@link DependencyResolutionError} If the dependency is not found.
     * @returns The mocked object corresponding to the provided symbol-based token.
     */
    get<TDependency>(token: symbol, identifierMetadata: IdentifierMetadata): StubbedInstance<TDependency>;
    /**
     * Retrieves a mocked dependency by its type, string, or symbol token with optional metadata.
     *
     * This method provides flexibility in retrieving dependencies by allowing various identifier types.
     *
     * @since 3.0.0
     * @template TDependency The type of the dependency being retrieved.
     * @param identifier - The token representing the dependency. It can be of type `Type<TDependency>`, `string`, or `symbol`.
     * @param identifierMetadata - A corresponding metadata object for the token identifier.
     * @throws {@link DependencyResolutionError} If the dependency is not found.
     * @returns The mocked instance corresponding to the provided identifier and metadata.
     */
    get<TDependency>(identifier: Type<TDependency> | string | symbol, identifierMetadata?: IdentifierMetadata): StubbedInstance<TDependency>;
    /**
     * Retrieves a mocked dependency by its type, string, or symbol token.
     *
     * This method provides flexibility in retrieving dependencies by allowing various identifier types.
     *
     * @since 3.0.0
     * @template TDependency The type of the dependency being retrieved.
     * @param identifier - The token representing the dependency. It can be of type `Type<TDependency>`, `string`, or `symbol`.
     * @throws {@link DependencyResolutionError} If the dependency is not found.
     * @returns The mocked instance corresponding to the provided identifier.
     */
    get<TDependency>(identifier: Type<TDependency> | string | symbol): StubbedInstance<TDependency>;
}
/**
 * A factory interface for creating UnitTestBed instances for testing classes.
 *
 * @see {@link https://suites.dev/docs/api-reference/testbed-solitary | TestBed Solitary}
 * @see {@link https://suites.dev/docs/api-reference/testbed-sociable | TestBed Sociable}
 * @since 3.0.0
 * @example
 * ```ts
 * import { TestBed } from '@suites/unit';
 * import { MyService } from './my-service.js';
 *
 * const { unit, unitRef } = await TestBed.solitary(MyService).compile();
 * ```
 */
export interface TestBed {
    /**
     * Creates a new TestBedBuilder instance for the given target class. This builder helps in configuring
     * and compiling the test environment for a class that should be tested in isolation (solitary).
     * It sets up the necessary dependencies and mocks, ensuring that the class under test is the primary
     * focus without interference from other components.
     *
     * @see {@link https://suites.dev/docs/api-reference/testbed-solitary | TestBed.solitary() API Reference}
     * @since 3.0.0
     * @template TClass - The class to be tested.
     * @param targetClass - The class to be tested.
     * @returns The TestBedBuilder instance configured for solitary testing.
     * @example
     * ```ts
     * import { TestBed } from '@suites/unit';
     * import { MyService } from './my-service.js';
     *
     * // MyService is now tested in isolation with all its dependencies mocked.
     * const { unit, unitRef } = await TestBed.solitary(MyService).compile();
     * ```
     */
    solitary<TClass>(targetClass: Type<TClass>): SolitaryTestBedBuilder<TClass>;
    /**
     * Creates a TestBedBuilder instance for the given target class for sociable testing.
     * Sociable testing allows for the inclusion of real implementations or partial mocks of certain dependencies.
     * This method returns a subset of the SociableTestBedBuilder's methods, focusing on exposing
     * specific dependencies that should be included in their real or partially mocked state.
     *
     * @see {@link https://suites.dev/docs/api-reference/testbed-sociable | TestBed.sociable() API Reference}
     * @template TClass - The type of the target class.
     * @param targetClass - The target class to be tested.
     * @returns A subset of the SociableTestBedBuilder's methods
     * containing only the 'expose' method.
     * @since 3.0.0
     * @example
     * ```ts
     * import { TestBed } from '@suites/unit';
     * import { MyService } from './my-service.js';
     * import { AnotherService } from './another-service.js';
     *
     * const { unit, unitRef } = await TestBed.sociable(MyService).expose(AnotherService).compile();
     * // MyService is now tested with AnotherService exposed and not fully mocked.
     * ```
     */
    sociable<TClass>(targetClass: Type<TClass>): SociableTestBedBuilder<TClass>;
}
/**
 * Represents the outcome when a `TestBedBuilder` is compiled.
 *
 * @template TClass The class type being tested.
 * @since 3.0.0
 * @see {@link https://suites.dev/docs/api-reference | API Reference}
 */
export interface UnitTestBed<TClass> {
    /**
     * The instance of the class under test.
     *
     * @template TClass The class being tested.
     * @property TClass unit
     */
    unit: TClass;
    /**
     * A reference to the dependencies associated with the class under test.
     *
     * @property unitRef - A reference to the mocked dependencies of the class
     */
    unitRef: UnitReference;
}
/**
 * Interface to define overrides for mocking dependencies in a test environment.
 *
 * @see {@link https://suites.dev/docs/api-reference/mock-configuration | Mock Configuration}
 * @template TDependency The type of the dependency to be mocked.
 * @template TClass The type of the class under test.
 */
export interface MockOverride<TDependency, TClass> extends MockOverrideCore<TDependency, TClass> {
    /**
     * Provides a mock implementation using stub functions for methods.
     *
     * Use this when you need fine-grained control over method behavior with stub functions.
     * The stub function is automatically provided for creating mocked methods.
     *
     * @see {@link https://suites.dev/docs/api-reference/mock-configuration | Mock Configuration}
     * @since 3.0.0
     * @param mockImplementation - Function that receives a stub creator and returns the mock
     * @returns A TestBedBuilder instance for chaining
     *
     * @example
     * ```ts
     * await TestBed.solitary(MyService)
     *   .mock(Logger)
     *   .impl((stub) => ({ log: stub().mockReturnValue(undefined) }))
     *   .compile();
     * ```
     */
    impl(mockImplementation: (stubFn: Stub<any, ArgsType<TDependency>>) => DeepPartial<TDependency>): TestBedBuilder<TClass>;
    /**
     * Provides a final implementation with concrete values or functions.
     *
     * Use this when you want to directly provide the mock implementation without stubs,
     * useful for simple mocks or when providing constant values.
     *
     * @see {@link https://suites.dev/docs/api-reference/mock-configuration | Mock Configuration}
     * @since 3.0.0
     * @param finalImplementation - The mock implementation object
     * @returns A TestBedBuilder instance for chaining
     *
     * @example
     * ```ts
     * await TestBed.solitary(MyService)
     *   .mock('CONFIG')
     *   .final({ apiUrl: 'http://test.api', timeout: 5000 })
     *   .compile();
     * ```
     */
    final(finalImplementation: DeepPartial<TDependency>): TestBedBuilder<TClass>;
}
/**
 * Provides methods to configure and finalize the `TestBed`.
 *
 * @template TClass The class type being tested.
 * @since 3.0.0
 * @see {@link https://suites.dev/docs/api-reference/mock-configuration | Mock Configuration}
 */
export interface TestBedBuilder<TClass> extends TestBedBuilderCore<TClass> {
    /**
     * Declares a dependency to be mocked using its type.
     *
     * @since 3.0.0
     * @param type - The type of the dependency.
     * @template TDependency The type of the dependency being mocked.
     * @returns An instance of MockOverride for further configuration.
     */
    mock<TDependency>(type: Type<TDependency>): MockOverride<TDependency, TClass>;
    /**
     * Declares a dependency to be mocked using its type along with a corresponding metadata object.
     *
     * @since 3.0.0
     * @param type - The type of the dependency.
     * @param identifierMetadata - the identifier metadata.
     * @template TDependency The type of the dependency being mocked.
     * @returns An instance of MockOverride for further configuration.
     */
    mock<TDependency>(type: Type<TDependency>, identifierMetadata: IdentifierMetadata): MockOverride<TDependency, TClass>;
    /**
     * Declares a dependency to be mocked using a string-based token.
     *
     * @since 3.0.0
     * @param token - The token string representing the dependency to be mocked.
     * @template TDependency The type of the dependency being mocked.
     * @returns An instance of MockOverride for further configuration.
     */
    mock<TDependency>(token: string): MockOverride<TDependency, TClass>;
    /**
     * Declares a dependency to be mocked using a string-based token along with a corresponding
     * metadata object.
     *
     * @since 3.0.0
     * @param token - The token string representing the dependency to be mocked.
     * @param identifierMetadata - the identifier metadata.
     * @template TDependency The type of the dependency being mocked.
     * @returns An instance of MockOverride for further configuration.
     */
    mock<TDependency>(token: string, identifierMetadata: IdentifierMetadata): MockOverride<TDependency, TClass>;
    /**
     * Declares a dependency to be mocked using a symbol-based token.
     *
     * @since 3.0.0
     * @param token - The token symbol representing the dependency to be mocked.
     * @template TDependency The type of the dependency being mocked.
     * @returns An instance of MockOverride for further configuration.
     */
    mock<TDependency>(token: symbol): MockOverride<TDependency, TClass>;
    /**
     * Declares a dependency to be mocked using a symbol-based token along with a corresponding
     * metadata object.
     *
     * @since 3.0.0
     * @param token - The token symbol representing the dependency to be mocked.
     * @param identifierMetadata - the identifier metadata if exists.
     * @template TDependency The type of the dependency being mocked.
     * @returns An instance of MockOverride for further configuration.
     */
    mock<TDependency>(token: symbol, identifierMetadata: IdentifierMetadata): MockOverride<TDependency, TClass>;
    /**
     * Declares a dependency to be mocked using a flexible identifier.
     *
     * @since 3.0.0
     * @param identifier - The identifier representing the dependency. It can be of type
     * `Type<TDependency>`, `string`, or `symbol`.
     * @param identifierMetadata - the identifier metadata if exists.
     * @template TDependency The type of the dependency being mocked.
     * @returns An instance of MockOverride for further configuration.
     */
    mock<TDependency>(identifier: Type<TDependency> | string | symbol, identifierMetadata?: IdentifierMetadata): MockOverride<TDependency, TClass>;
    /**
     * Finalizes the test environment configuration and builds the test instance.
     *
     * This method completes the builder chain and returns the configured test environment
     * with the unit under test and references to all mocked dependencies.
     *
     * @since 3.0.0
     * @returns A Promise resolving to UnitTestBed with unit and unitRef
     */
    compile(): Promise<UnitTestBed<TClass>>;
}
