import type { RequestCacheStorage, RequestOptions } from "../core/RequestCore";
import type { RequestImplementer } from "../core/RequestImplementer";
import { isNullOrEmpty } from "../utils/Utils";

export class Response {
  public constructor(url: string, data: unknown, options: {
    headers: Record<string, unknown>,
    status: number,
  }, errMsg: string) {
    this.errMsg = errMsg;
    this.data = data;
    this.url = url;
    this.status = options.status;
    this.headers = options.headers;
    this.ok = options.status >= 200 && options.status <= 399;
  }

  headers: Record<string, unknown>;
  ok: boolean;
  status: number;
  errMsg: string;
  url: string;
  data: unknown;

  json() : Promise<any> {
    return new Promise<any>((resolve, reject) => {
      if (typeof this.data === 'undefined' || isNullOrEmpty(this.data)) {
        resolve({});
        return;
      }
      if (typeof this.data === 'object') {
        resolve(this.data);
        return;
      }
      let data = null;
      
      if (typeof this.data === 'string') {
        try {
          data = JSON.parse(this.data);
        } catch(e) {
          console.log('json error: ' + e,  this.data);
          
          reject(e);
        }
      } else {
        data = this.data;
      }

      resolve(data);
    })
  }
}

const uniappImplementer : RequestImplementer = {
  getCache: function (key: string) {
    return new Promise<RequestCacheStorage|null>((resolve, reject) => {
      uni.getStorage({
        key: key,
        success: (res) => {
          resolve(res.data ? JSON.parse(res.data) as RequestCacheStorage : null);
        },
        fail: (res) => {
          resolve(null);
        }
      });
    });
  },
  setCache: async function (key: string, value: RequestCacheStorage|null) {
    return new Promise<void>((resolve, reject) => {
      uni.setStorage({
        key: key,
        data: JSON.stringify(value),
        success: (res) => {
          resolve();
        },
        fail: (res) => {
          resolve();
        }
      });
    });
  },
  doRequest: function (url: string, init?: RequestOptions, timeout?: number): Promise<Response> {
    return new Promise<Response>((resolve, reject) => {
      uni.request({
        url: url,
        timeout: timeout,
        ...init,
        success(res) {
          const response = new Response(url, res.data, {
            headers: res.header,
            status: res.statusCode,
          }, 'success');
          resolve(response);
        },
        fail(res) {
          reject(res);
        },
      })
    });
  }
};

export default uniappImplementer;