import {TaskQueue, TaskQueueConfig} from "./taskQueue";
import {
    FetchAdapter,
    FetchAdapterConfig,
    FetchAdapterRequestConfig,
    FetchAdapterResponse,
    RequestMeta
} from "./fetchAdapter";

export declare interface NextNetworkConfig {
    taskQueue?: TaskQueue,
    taskQueueConfig?: TaskQueueConfig,

    fetchAdapter?: FetchAdapter,
    fetchAdapterConfig?: FetchAdapterConfig,

    //接口测速
    enablePingTest?: boolean
    isIgnorePingTestHttpErrors?: boolean
}

/**
 * ## NextNetwork **网络管理器**
 * **/
export class NextNetwork {
    public readonly taskQueue!: TaskQueue
    public readonly fetchAdapter!: FetchAdapter

    public readonly enablePingTest?: boolean = true
    public readonly isIgnorePingTestHttpErrors?: boolean = false

    constructor(config?: NextNetworkConfig) {
        if (config) {
            const {taskQueue, taskQueueConfig, fetchAdapter, fetchAdapterConfig, enablePingTest, isIgnorePingTestHttpErrors} = config
            if (taskQueue) {
                this.taskQueue = taskQueue
            }

            this.taskQueue = new TaskQueue(taskQueueConfig ?? {})

            if (fetchAdapter) {
                this.fetchAdapter = fetchAdapter
            } else {
                this.fetchAdapter = new FetchAdapter(fetchAdapterConfig ?? {})
            }

            this.enablePingTest = enablePingTest ?? this.enablePingTest
            this.isIgnorePingTestHttpErrors = isIgnorePingTestHttpErrors ?? this.isIgnorePingTestHttpErrors

            if (this.enablePingTest) {
                this.createPreConditionTask({asyncFunction: async () => await this.fetchAdapter.runPingTest({isIgnoreHttpErrors: isIgnorePingTestHttpErrors})})
            }
        }
    }

    //创建一个前置任务 一般用来处理更新token或者获取系统信息的时候才会用到
    //该任务执行期间不会执行其他任务
    public async createPreConditionTask({asyncFunction}: { asyncFunction: (Task) => Promise<any | void> }) {
        return await this.taskQueue.createTask({asyncFunction, isPreCondition: true})
    }

    public async request(fetchAdapterRequestConfig: FetchAdapterRequestConfig, parentTaskId?: string): Promise<{ response: FetchAdapterResponse, request: Request, requestMeta?: RequestMeta }> {
        return await this.taskQueue.createTask({
            asyncFunction: async () => await this.fetchAdapter.request(fetchAdapterRequestConfig),
            parentTaskId
        })
    }

    public async get(url: string, params?: Object | BodyInit | null, enableCancelRepeatRequest?: boolean, parentTaskId?: string): Promise<{ response: FetchAdapterResponse, request: Request, requestMeta?: RequestMeta }> {
        return await this.taskQueue.createTask({
            asyncFunction: async () => await this.fetchAdapter.get(url, params, enableCancelRepeatRequest),
            parentTaskId
        })
    }

    public async post(url: string, params?: Object | BodyInit | null, enableCancelRepeatRequest?: boolean, parentTaskId?: string): Promise<{ response: FetchAdapterResponse, request: Request, requestMeta?: RequestMeta }> {
        return await this.taskQueue.createTask({
            asyncFunction: async () => await this.fetchAdapter.post(url, params, enableCancelRepeatRequest),
            parentTaskId
        })
    }

    public async put(url: string, params?: Object | BodyInit | null, enableCancelRepeatRequest?: boolean, parentTaskId?: string): Promise<{ response: FetchAdapterResponse, request: Request, requestMeta?: RequestMeta }> {
        return await this.taskQueue.createTask({
            asyncFunction: async () => await this.fetchAdapter.put(url, params, enableCancelRepeatRequest),
            parentTaskId
        })
    }

    public async delete(url: string, params?: Object | BodyInit | null, enableCancelRepeatRequest?: boolean, parentTaskId?: string): Promise<{ response: FetchAdapterResponse, request: Request, requestMeta?: RequestMeta }> {
        return await this.taskQueue.createTask({
            asyncFunction: async () => await this.fetchAdapter.delete(url, params, enableCancelRepeatRequest),
            parentTaskId
        })
    }

    public async search(url: string, params?: Object | BodyInit | null, enableCancelRepeatRequest?: boolean, parentTaskId?: string): Promise<{ response: FetchAdapterResponse, request: Request, requestMeta?: RequestMeta }> {
        return await this.taskQueue.createTask({
            asyncFunction: async () => await this.fetchAdapter.search(url, params, enableCancelRepeatRequest),
            parentTaskId
        })
    }

    public async patch(url: string, params?: Object | BodyInit | null, enableCancelRepeatRequest?: boolean, parentTaskId?: string): Promise<{ response: FetchAdapterResponse, request: Request, requestMeta?: RequestMeta }> {
        return await this.taskQueue.createTask({
            asyncFunction: async () => await this.fetchAdapter.patch(url, params, enableCancelRepeatRequest),
            parentTaskId
        })
    }
}
