import { HollywoodOf, AnyHollywood, RegisterTokens, InferContainer, ContainerOptions, Hollywood } from 'hollywood-di';
import { Hono } from 'hono';

type Spread<T> = {
    [K in keyof T]: T[K];
} & {};
type Merge<T, To> = T & Omit<To, keyof T>;
type IsEmptyObject<T> = keyof T extends never ? true : false;
type KnownKey<T> = string extends T ? never : number extends T ? never : symbol extends T ? never : T;
type KnownMappedKeys<T> = {
    [K in keyof T as KnownKey<K>]: T[K];
} & {};

type SubModule<T extends Record<string, any> = any> = {
    app: (container: IsEmptyObject<T> extends true ? HollywoodOf<any> | undefined : HollywoodOf<T>) => Hono<any, any, any>;
};
type SubModules<TContainer extends Record<string, any> = any> = Record<string, SubModule<TContainer>>;
type InferSubModules<R extends SubModules = {}> = {
    [K in keyof R]: R[K] extends Module<infer App, any, any> ? App : never;
} & {};
declare class Module<App extends Hono<any, any, any>, Deps extends Record<string, any>, Modules extends SubModules> {
    private _context;
    private _route;
    constructor(_context: [
        tokens: {
            tokens: RegisterTokens<any, any>;
            options?: ContainerOptions;
        } | undefined,
        routes: SubModules<any>
    ][], _route: (container: Deps, modules: InferSubModules<Modules>) => App);
    app(container: IsEmptyObject<Deps> extends true ? HollywoodOf<any> | undefined : HollywoodOf<Deps>): App;
    app(): IsEmptyObject<Deps> extends true ? App : never;
}
declare class ModuleBuilder<App extends Hono<any, any, any>, Deps extends Record<string, any>, Modules extends SubModules, Container extends AnyHollywood | undefined> {
    private app;
    constructor(app: App);
    private context;
    use<T extends Container extends AnyHollywood ? never : Record<string, any>>(): Container extends AnyHollywood ? never : ModuleBuilder<App, T, Modules, HollywoodOf<T>>;
    provide<T extends Record<string, any> = {}>(tokens: RegisterTokens<T, Container extends AnyHollywood ? InferContainer<Container> : Deps>, options?: ContainerOptions): ModuleBuilder<App, Deps, Modules, Container extends AnyHollywood ? Hollywood<T, InferContainer<Container>> : Hollywood<T, {}>>;
    submodules<T extends SubModules<Container extends AnyHollywood ? KnownMappedKeys<InferContainer<Container>> : Deps>>(modules: T): ModuleBuilder<App, Deps, Spread<Merge<T, Modules>>, Container>;
    route<T extends Hono<any, any, any>>(fn: (app: App, container: Container extends AnyHollywood ? KnownMappedKeys<InferContainer<Container>> : Deps, modules: InferSubModules<Modules>) => T): Module<T, Deps, Modules>;
}
declare function createModule<App extends Hono<any, any, any> = Hono>(app: App): ModuleBuilder<App, {}, {}, undefined>;
declare function createModule(): ModuleBuilder<Hono, {}, {}, undefined>;

export { createModule };
