import { BaseRequestFactory } from '../base/base-request-factory';

import { NetworkAddInterceptorType } from '../types';

import type { IInterceptor, INetworkManagerOptions, IBaseRequestParam } from '../types';

/**
 * 网络请求管理类
 * @docgen
 * @class NetworkManager
 */
export class NetworkManager {
  // 单例
  private static sInstance: NetworkManager;

  // 生产执行请求实例的工厂
  // @ts-ignore
  private requestFactory: BaseRequestFactory;
  private requestDecorator: ((...args: any) => any) | null = null;

  private customInterceptor: {
    // 业务侧自定义添加的请求拦截处理，Head在处理队列最前面，Tail在最后面
    customRequestInterceptorsHead: IInterceptor[],
    customRequestInterceptorsTail: IInterceptor[],
    // 业务侧自定义添加的返回拦截处理，Head在处理队列最前面，Tail在最后面
    customResponseInterceptorsHead: IInterceptor[],
    customResponseInterceptorsTail: IInterceptor[],
    // 业务侧自定义添加的错误拦截处理，Head在处理队列最前面，Tail在最后面
    customErrorInterceptorsHead: IInterceptor[],
    customErrorInterceptorsTail: IInterceptor[],
  } = {
      customRequestInterceptorsHead: [],
      customRequestInterceptorsTail: [],
      customResponseInterceptorsHead: [],
      customResponseInterceptorsTail: [],
      customErrorInterceptorsHead: [],
      customErrorInterceptorsTail: [],
    };

  /**
   * 获取单例
   **/
  public static get instance(): NetworkManager {
    if (!this.sInstance) {
      this.sInstance = new NetworkManager();
    }

    return this.sInstance;
  }

  constructor(options?: INetworkManagerOptions) {
    if (options?.requestFactory) {
      this.setRequestFactory(options.requestFactory);
    }
  }

  /**
   * 设置网络请求生成工厂
   * @param factory 生成请求处理的工厂
   */
  public setRequestFactory(factory: BaseRequestFactory) {
    this.requestFactory = factory;
  }

  public setDecorator(requestDecorator: any) {
    this.requestDecorator = requestDecorator;
  }

  /**
   * 发送一次请求
   * @param param 请求参数
   */
  public async request(param: IBaseRequestParam): Promise<any> {
    const request = this.requestFactory.create(param);
    if (this.requestDecorator) {
      return this.requestDecorator(() => request.send(param, this.customInterceptor), param);
    }
    return await request.send(param, this.customInterceptor);
  }

  /**
   * 添加自定义发送请求前拦截处理
   * @param interceptor 自定义处理回调
   * @param type 可加到发送请求前拦截处理队列的头部或者末尾
   */
  public addRequestInterceptor(interceptor: IInterceptor, type: NetworkAddInterceptorType) {
    switch (type) {
      case NetworkAddInterceptorType.Head:
        this.customInterceptor?.customRequestInterceptorsHead?.push(interceptor);
        break;
      case NetworkAddInterceptorType.Tail:
        this.customInterceptor?.customRequestInterceptorsTail?.push(interceptor);
        break;
    }
  }

  /**
   * 添加自定义数据返回后拦截处理
   * @param interceptor 自定义处理回调
   * @param type 可加到数据返回后拦截处理队列的头部或者末尾
   */
  public addResponseInterceptor(interceptor: IInterceptor, type: NetworkAddInterceptorType) {
    switch (type) {
      case NetworkAddInterceptorType.Head:
        this.customInterceptor?.customResponseInterceptorsHead?.push(interceptor);
        break;
      case NetworkAddInterceptorType.Tail:
        this.customInterceptor?.customResponseInterceptorsTail?.push(interceptor);
        break;
    }
  }

  /**
   * 添加自定义异常错误拦截处理
   * @param interceptor 自定义处理回调
   * @param type 可加到错误拦截处理队列的头部或者末尾
   */
  public addErrorInterceptor(interceptor: IInterceptor, type: NetworkAddInterceptorType) {
    switch (type) {
      case NetworkAddInterceptorType.Head:
        this.customInterceptor?.customErrorInterceptorsHead?.push(interceptor);
        break;
      case NetworkAddInterceptorType.Tail:
        this.customInterceptor?.customErrorInterceptorsTail?.push(interceptor);
        break;
    }
  }
}

/**
 * 封装统一的请求接口
 * @docgen
 * @function request
 * @param {IBaseRequestParam} param 请求参数
 * @return {*}  {Promise} 成功resolve，失败reject
 *
 * @example
 * post({
 *  url,
 *  reqData,
 *  showMsgToast:false,
 * })
 *  .then((res) => {})
 *  .catch((err) => {})
 */
export function request(param: IBaseRequestParam): Promise<any> {
  return NetworkManager.instance.request(param);
}

export const post = request;
export const get = request;

