import 'dart:convert';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/util/not_found_exception.dart';
import 'package:http/http.dart' as http;
import 'package:aitrainer_app/model/cache.dart';

class APIClient with Common, Logging {
  Future<String> get(String endPoint, String param) async {
    final url = Cache.getBaseUrl() + endPoint + param;

    trace("-------- API get " + url);
    String authToken = Cache().getAuthToken();
    if (authToken.length == 0) {
      var responseJson = await this.authenticateUser(Cache.username, Cache.password);
      authToken = responseJson['token'];
      Cache().authToken = authToken;
    }
    var uri = Uri.parse(url);
    final response = await http.get(uri, headers: {'Content-Type': 'application/json', 'Authorization': "Bearer " + authToken});
    trace(" ------------get response code: " + response.statusCode.toString());
    if (response.statusCode == 200) {
      return utf8.decode(response.bodyBytes);
    } else if (response.statusCode == 404) {
      throw NotFoundException(message: "Not Found");
    } else {
      throw Exception("Network Error, please try again later");
    }
  }

  Future<String> post(String endPoint, String body) async {
    final url = Cache.getBaseUrl() + endPoint;
    trace(" ------------ http/post body $body - url: $url ");
    String authToken = Cache().getAuthToken();
    if (authToken.length == 0) {
      var responseJson = await this.authenticateUser(Cache.username, Cache.password);
      authToken = responseJson['token'];
    }
    var uri = Uri.parse(url);
    final response = await http.post(
      uri,
      headers: {'Content-Type': 'application/json; charset=UTF-8', 'Authorization': "Bearer " + authToken},
      body: body,
    );
    trace(" ------------post response code: " + response.statusCode.toString());
    final String decodedResponse = utf8convert(response.body);
    trace(" ------------ response: $decodedResponse");
    return decodedResponse;
  }

  dynamic authenticateUser(String email, String password) async {
    var url = Cache.getBaseUrl() + "authenticate";

    try {
      final body = '{"username":"$email", "password":"$password"}';
      trace("authentication with $email");
      var uri = Uri.parse(url);
      final response = await http.post(uri, headers: {'Authorization': '1', 'Content-Type': 'application/json'}, body: body);
      final responseCode = response.statusCode;
      if (responseCode != 200) {
        trace("authentication response: $responseCode");
        throw Exception("Network error, try again later!");
        /* return {
          "error": "Authentication error, total failure",
        }; */
      }

      final responseJson = json.decode(response.body);
      return responseJson;
    } catch (exception) {
      print(exception.toString());
      throw Exception("Network error, try again later!");
    }
  }

  Future<String?> fetch(var authToken, var endPoint) async {
    var url = Cache.getBaseUrl() + endPoint;

    try {
      var uri = Uri.parse(url);
      final response = await http.get(
        uri,
        headers: {'Authorization': authToken},
      );

      final responseJson = json.decode(response.body);
      return responseJson;
    } catch (exception) {
      log(exception.toString());
      if (exception.toString().contains('SocketException')) {
        return 'NetworkError';
      } else {
        return null;
      }
    }
  }
}