import { InstanceMeta } from '@typesugar/macros';

/**
 * FlatMap Typeclass
 *
 * Provides sequencing/chaining operations for type constructors.
 * This is the minimal typeclass required for do-notation (`let:/yield:`).
 *
 * Unlike Monad, FlatMap doesn't require `pure`/`of` — it only needs
 * `map` and `flatMap`. This makes it usable with types that support
 * chaining but don't have a natural way to lift pure values.
 *
 * ## Instances
 *
 * Built-in instances are provided for:
 * - Array<A> — flatMap is Array.prototype.flatMap
 * - Promise<A> — flatMap is Promise.prototype.then
 * - Iterable<A> — lazy flatMap via generator functions
 * - AsyncIterable<A> — async lazy flatMap via async generators
 *
 * ## Usage with let:/yield:
 *
 * ```typescript
 * // With Array
 * let: {
 *   x << [1, 2, 3]
 *   y << [x * 10, x * 20]
 * }
 * yield: ({ x, y })
 * // → [{ x: 1, y: 10 }, { x: 1, y: 20 }, { x: 2, y: 20 }, ...]
 *
 * // With Promise
 * let: {
 *   user << fetchUser(id)
 *   posts << fetchPosts(user.id)
 * }
 * yield: ({ user, posts })
 * // → Promise<{ user, posts }>
 * ```
 */

/**
 * FlatMap typeclass — sequencing for type constructors.
 *
 * **@macro-only** — This interface is designed for macro-only use and is not
 * intended for direct consumption by end users. The `F` type parameter is
 * phantom (unused in the interface body) and all values are typed as `unknown`
 * because the let:/yield: macro handles type safety at the call site through
 * compile-time code generation.
 *
 * This is the minimal typeclass required for do-notation (`let:/yield:`).
 * It uses a simplified interface without HKT to avoid TypeScript's
 * type instantiation depth limits.
 *
 * Laws:
 * - Associativity: flatMap(flatMap(fa, f), g) = flatMap(fa, a => flatMap(f(a), g))
 * - Consistency: map(fa, f) = flatMap(fa, a => pure(f(a))) [when pure exists]
 *
 * Use `registerStdInstances()` macro to enable summon<FlatMap<F>>() resolution.
 * @internal
 */
interface FlatMap<F> {
    /**
     * Transform the wrapped value.
     * @param fa The wrapped value
     * @param f The transformation function
     */
    map<A, B>(fa: unknown, f: (a: A) => B): unknown;
    /**
     * Sequence operations, flattening the result.
     * @param fa The wrapped value
     * @param f A function returning a new wrapped value
     */
    flatMap<A, B>(fa: unknown, f: (a: A) => unknown): unknown;
}
/**
 * @internal Phantom tag for Array FlatMap instance.
 * Not intended for external use — exists only to parameterize FlatMap<F>.
 */
interface _ArrayTag {
    readonly _tag: "Array";
}
/**
 * @internal Phantom tag for Promise FlatMap instance.
 * Not intended for external use — exists only to parameterize FlatMap<F>.
 */
interface _PromiseTag {
    readonly _tag: "Promise";
}
/**
 * @internal Phantom tag for Iterable FlatMap instance.
 * Not intended for external use — exists only to parameterize FlatMap<F>.
 */
interface _IterableTag {
    readonly _tag: "Iterable";
}
/**
 * @internal Phantom tag for AsyncIterable FlatMap instance.
 * Not intended for external use — exists only to parameterize FlatMap<F>.
 */
interface _AsyncIterableTag {
    readonly _tag: "AsyncIterable";
}
/**
 * FlatMap instance for Array.
 *
 * Uses the native Array.prototype.map and Array.prototype.flatMap.
 * This compiles to direct method calls — zero overhead.
 */
declare const flatMapArray: FlatMap<_ArrayTag>;
/**
 * FlatMap instance for Promise.
 *
 * Uses Promise.prototype.then for both map and flatMap.
 * Promise automatically flattens nested promises, so
 * map and flatMap have the same implementation.
 */
declare const flatMapPromise: FlatMap<_PromiseTag>;
/**
 * FlatMap instance for Iterable.
 *
 * Uses generator functions for lazy evaluation.
 * Elements are produced on demand, not eagerly.
 */
declare const flatMapIterable: FlatMap<_IterableTag>;
/**
 * FlatMap instance for AsyncIterable.
 *
 * Uses async generator functions for lazy async evaluation.
 * Useful for streaming data processing.
 */
declare const flatMapAsyncIterable: FlatMap<_AsyncIterableTag>;
/**
 * Register a FlatMap instance for a type constructor.
 *
 * @param name The name of the type constructor (e.g., "Option", "Effect")
 * @param instance The FlatMap instance
 * @param meta Optional metadata (e.g., method name overrides)
 *
 * @deprecated Use @instance decorator or registerInstanceWithMeta() from @typesugar/macros
 * for new code. This function is maintained for backward compatibility.
 */
declare function registerFlatMap<F>(name: string, instance: FlatMap<F>, meta?: InstanceMeta): void;
/**
 * Get a FlatMap instance by type constructor name.
 *
 * @param name The name of the type constructor
 * @returns The FlatMap instance, or undefined if not found
 *
 * @deprecated Use findInstance("FlatMap", name) from @typesugar/macros for new code.
 * This function is maintained for backward compatibility.
 */
declare function getFlatMap(name: string): FlatMap<unknown> | undefined;
/**
 * Check if a FlatMap instance exists for a type constructor.
 * Uses the unified registry.
 */
declare function hasFlatMap(name: string): boolean;

export { type FlatMap, flatMapArray, flatMapAsyncIterable, flatMapIterable, flatMapPromise, getFlatMap, hasFlatMap, registerFlatMap };
