/* eslint-disable @typescript-eslint/no-explicit-any */
import type { InteropObservable, Observable } from 'rxjs';

/** 可转换为 Observable 的类型 */
export type ObservableLike<T> = Observable<T> | InteropObservable<T> | AsyncIterable<T>;

/** Returns a boolean for whether the two given types are equal. */
type IsEqual<A, B> = (<G>() => G extends A ? 1 : 2) extends <G>() => G extends B ? 1 : 2 ? true : false;

/** 作为通知输出的方法 */
type IsNotificationReturn<R> =
    IsEqual<R, void> extends true
        ? true
        : IsEqual<R, undefined> extends true
          ? true
          : R extends PromiseLike<void> | void
            ? true
            : false;

/** 作为 Observable 输出的方法 */
type ObservableReturn = ObservableLike<any> | PromiseLike<ObservableLike<any>>;

/** 提取类型中的方法 */
export type Methods<T> = {
    [P in keyof T]: T[P] extends (...args: any[]) => infer R ? (R extends ObservableReturn ? never : P) : never;
}[keyof T] &
    string;
/** 提取类型中的通知 */
export type Notifications<T> = {
    [P in keyof T]: T[P] extends (...args: any[]) => infer R
        ? IsNotificationReturn<R> extends true
            ? P
            : never
        : never;
}[keyof T] &
    string;
/** 提取类型中的订阅主题 */
export type Subjects<T> = {
    [P in keyof T]: T[P] extends (...args: any[]) => ObservableReturn ? P : never;
}[keyof T] &
    string;

/** RPC 调用的参数 */
export type RpcParameters<T> = T extends (...args: infer R) => any ? R : never;

/** RPC 调用的返回 */
type RpcReturnsMap<R> = Awaited<R> extends ObservableLike<infer U> ? U : Awaited<R>;
/** RPC 调用的返回 */
export type RpcReturns<T> = T extends (...args: any[]) => infer R ? RpcReturnsMap<R> : never;

/** RPC 调用函数的实现 */
type RpcField<T> = T extends (...args: infer P) => infer R
    ? Awaited<R> extends ObservableReturn
        ? (...args: P) => ObservableLike<RpcReturnsMap<R>> | PromiseLike<ObservableLike<RpcReturnsMap<R>>>
        : (...args: P) => RpcReturnsMap<R> | PromiseLike<RpcReturnsMap<R>>
    : never;

/** RPC 调用对象的实现 */
export type RpcObject<T> = {
    [K in keyof T as K & (Subjects<T> | Methods<T>)]: RpcField<T[K]>;
};

// interface A {
//     field: number;
//     /** methodA */
//     methodA(x: number): number | undefined;
//     methodB: (x: string, y: number) => Promise<number>;
//     readonly methodC: () => Iterable<number>;
//     readonly methodD: () => void | Promise<null | undefined>;
//     readonly notificationA: () => undefined;
//     readonly notificationB: () => Promise<void>;
//     notificationC(): void;
//     readonly notificationD: () => void | PromiseLike<undefined>;
//     readonly notificationE: () => void | Promise<void>;
//     subjectA(x: number): Observable<number>;
//     subjectB: (x: string) => Promise<Observable<number>>;
//     subjectC: () => PromiseLike<InteropObservable<number>>;
//     subjectD: () => AsyncGenerator<number>;
//     subjectE: () => PromiseLike<AsyncGenerator<number>>;
// }

// type X = Methods<A>;
// type Y = Subjects<A>;
// type Z = Notifications<A>;

// type R = RpcObject<A>;
// type Test = R['field'];

// declare const r: R;
// r.subjectA;
