import { Message } from 'wechaty';
import { Assistant } from './assistant';
import { ConversationContext } from './context';
import { MaybePromise } from './typescript';

export interface Hook<Exposed, Normalized = Exposed, Result = Normalized extends (...args: any) => infer U ? U extends Promise<infer V> ? V : U : void> {
    exposed: Exposed;
    normalized: Normalized;
    result: Result;
}
export type LifeCycleHook<T extends unknown[] = []> = Hook<(controller: AbortController, assistant: Assistant, ...args: T) => MaybePromise<void>>;
export type ExtendsHook<T> = Hook<(controller: AbortController, extendable: T, assistant: Assistant) => MaybePromise<void>>;
/**
 * List of hooks
 */
export interface Hooks {
    /**
     * 消息接收
     */
    onMessage: LifeCycleHook<[Message]>;
    /**
     * 私人消息
     */
    onIndividualMessage: LifeCycleHook<[Message]>;
    /**
     * 房间消息
     */
    onRoomMessage: LifeCycleHook<[Message]>;
    /**
     * 在房间被提及
     */
    onRoomMentionSelfMessage: LifeCycleHook<[Message]>;
    /**
     * 上下文创建后
     */
    onContextCreated: ExtendsHook<ConversationContext>;
    /**
     * 上下文销毁后
     */
    onContextDestroyed: ExtendsHook<ConversationContext>;
    /**
     * 处理文本消息
     */
    onPrepareTextMessage: ExtendsHook<ConversationContext>;
    /**
     * 处理文件消息
     */
    onPrepareFileMessage: ExtendsHook<ConversationContext>;
}
/**
 * Name of hooks
 */
export type HooksName = keyof Hooks;
/**
 * Exposed hooks API that can be accessed by a plugin
 */
export type HooksExposed = {
    [K in HooksName]: Hooks[K]['exposed'];
};
/**
 * Normalized hooks
 */
export type HooksNormalized = {
    [K in HooksName]: Hooks[K]['normalized'];
};
/**
 * Result of hooks
 */
export type HooksResult = {
    [K in HooksName]: Hooks[K]['result'];
};
/**
 * Hook item
 */
export interface HookItem<T extends HooksName> {
    pluginName: string;
    hook: HooksNormalized[T];
}
/**
 * Hook items queue
 */
export interface HookQueue<T extends HooksName> {
    name: T;
    items: HookItem<T>[];
    add: (item: HookItem<T>) => void;
    process: (...args: Parameters<HooksNormalized[T]>) => Promise<HooksResult[T][]>;
}
