
import 'dart:io';

import 'package:bot_toast/bot_toast.dart';
import 'package:dio/dio.dart';
import 'package:dio/adapter.dart';
import 'package:twong/api/index.dart';

import '../utils/index.dart';
import '../models/index.dart';

enum RequestType {
  GET, POST
}

class RequestData {
  final String api;
  final dynamic data;
  final RequestType type;

  RequestData(this.type, this.api, this.data);
}

class Request {
  static Dio _dio;
  static RequestData _lastRequest;
  static const String update_url = "https://qndownload.shotshock.shop/version";
  // init network
  static void init() {
    _dio = Dio(BaseOptions(
        sendTimeout: 15000,
        receiveTimeout: 15000,
        connectTimeout: 15000,
        // baseUrl: "http://twong.h/api/",
        // baseUrl: "https://twong.shotshock.shop/api/",
        baseUrl: "http://81.70.81.74:30007/api/",
        headers: {}));

    (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
        (client) {
      client.badCertificateCallback =
          (X509Certificate cert, String host, int port) {
        return true;
      };
    };
    updateToken();
  }
  // update token
  static void updateToken() {
    var token = Cache.token;
    if(token == null) {
      Request.setHeader("Authori-zation", null);
    } else {
      Request.setHeader("Authori-zation", "Bearer ${token?.token}");
    }
  }
  // set http header
  static void setHeader(String key, String value) {
    _dio.options.headers[key] = value;
  }
  // http get request with full url
  static Future<Response> getWithUrl(String url, {Map<String, dynamic> params}) async {
    return Dio().get(url, queryParameters: params);
  }
  // http post request with full url
  static Future<Response> postWithUrl(String url, {Map<String, dynamic> params}) async {
    return Dio().post(url, queryParameters: params);
  }
  // get remote version
  static Future<Version> getVersion() async {
    var response = await getWithUrl("$update_url?ts=${DateTime.now().millisecondsSinceEpoch}");
    var version = Version.fromJson(response.data);
    return version;
  }
  // base HTTP GET
  static Future<dynamic> get(String uri, {Map<String, dynamic> params}) async {
    try {
      _lastRequest = RequestData(RequestType.GET, uri, params);
      // var response = await _dio.get(uri, queryParameters: params);
      // var response = await compute(_request, RequestData(_dio, "GET", uri, data: params));
      // var data = Resp.fromJson(response.data);
      var data = await _processRequestData(_lastRequest);
      return Future.value(process(data));
    } on DioError catch (err) {
      Log.e("DioError: $err URL: ${_dio.options.baseUrl}$uri");
      throw NetError("网络错误！");
    }
  }
  // base HTTP POST
  static Future<dynamic> post(String uri, {Map<String, dynamic> params}) async {
    try {
      _lastRequest = RequestData(RequestType.POST, uri, params);
      // var response = await _dio.post(uri, queryParameters: params);
      // var response = await compute(_request, RequestData(_dio, "POST", uri, data: params));
      var data = await _processRequestData(_lastRequest);
      return Future.value(process(data));
    } on DioError catch (err) {
      Log.e("DioError: $err URL: ${_dio.options.baseUrl}$uri");
      throw NetError("网络错误！");
    }
  }

  static Future<Resp> _processRequestData(RequestData request) async {
    var resp;
    if(request.type == RequestType.GET) {
      Log.i("GET | ${request.api} " + (request.data == null ? "" : request.data.toString()));
      var response = await _dio.get(request.api, queryParameters: request.data);
      resp = Resp.fromJson(response.data);
    } else if(request.type == RequestType.POST) {
      Log.i("POST | ${request.api} " + (request.data == null ? "" : request.data.toString()));
      var response = await _dio.post(request.api, queryParameters: request.data);
      resp = Resp.fromJson(response.data);
    }
    return resp;
  }

  // process http response data
  static dynamic process(Resp response) async {
    Log.i("rsp | ${response.msg} ${response.status}");

    if([410000, 410001, 410002].contains(response.status)) {
      var request = _lastRequest;
      var resp = await Network.inst.autoLogin();
      if(resp == null){
        Utils.toLogin();
        BotToast.showText(text: response.msg);
        throw NetError(response.msg);
      }
      if(request != null) {
        response = await _processRequestData(request);
        Log.i("rsp | ${response.msg} ${response.status}");
      }
    }

    if (response.status != 200) {
      Log.e("response ${response.toJson()}}");
      BotToast.showText(text: response.msg);
      throw NetError(response.msg);
    }

    return response.data;
  }
}