import 'dart:convert';
import 'dart:io';
import 'package:car_provider_app/models/response_models.dart';
import 'package:car_provider_app/services/secure_storage.dart';
import 'package:http/http.dart';
import 'package:injector/injector.dart';

import 'http_service.dart';
import 'network_service.dart';

abstract class IBackendApiService {
  Future<BackendResponse> getUnauthenticatedAPI(String route);

  Future<BackendResponse> getAuthenticatedAPI(String route);

  Future<BackendResponse> postUnauthenticatedAPI(
      String route, String dataAsJson);

  Future<BackendResponse> postAuthenticatedAPI(String route, String dataAsJson);

  Future<BackendResponse> deleteAuthenticatedAPI(String route, String id);
}

class BackendApiService implements IBackendApiService {
  static String _homeUrl = "https://check.revotec.eu/check2/";
  static String _serverApiBaseUrl = _homeUrl + "mapi/v1/";

  static String get homeUrl => _homeUrl;

  final ISecureStorage _secureStorage =
      Injector.appInstance.getDependency<ISecureStorage>();
  final IHttpService _httpService =
      Injector.appInstance.getDependency<IHttpService>();

  ///internal helper functions which executes the given api call
  ///and wraps the response
  Future<BackendResponse> _callApi(Future<dynamic> callback) async {
    Response response;
    try {
      //execute future
      response = await callback;
      //check response code, and if not ok return isOk = false
      //200 for Get
      //201 for Post

      // print("res121: " +
      //     response.statusCode.toString() +
      //     " Body:" +
      //     response.body.toString());
      //if delete request sent so server is returning 204 in case of success.
      if (response.statusCode == 204)
        return BackendResponse(id: 1, isOk: true, result: null);

      if (response.statusCode != 200 && response.statusCode != 201)
        return BackendResponse(id: -1, isOk: false, result: null);
      //if response code is good then parse message and return parsed response
      return BackendResponse.fromJson(json.decode(response.body));
      //return BackendResponse.fromJson(dioResponse.body);
    } catch (e) {
      return BackendResponse(id: -1, isOk: false, result: null);
      // try {
      //   return BackendResponse.fromJson(json.decode(response.body));
      // } catch (e) {
      //   return BackendResponse(id:-1, isOk:false,result: null);
      // }
    }
  }

  @override
  Future<BackendResponse> getAuthenticatedAPI(String route) async {
    await checkConnection();
    final token = await _secureStorage.readBearerToken();
    return _callApi(_httpService.get(_serverApiBaseUrl + route, headers: {
      'Content-Type': 'application/json',
      'Accept': '*/*',
      HttpHeaders.authorizationHeader: "Bearer $token"
    }));
  }

  @override
  Future<BackendResponse> getUnauthenticatedAPI(String route) async {
    await checkConnection();
    return _callApi(_httpService.get(_serverApiBaseUrl + route,
        headers: {'Content-Type': 'application/json', 'Accept': '*/*'}));
  }

  @override
  Future<BackendResponse> postAuthenticatedAPI(
      String route, String dataAsJson) async {
    await checkConnection();
    final token = await _secureStorage.readBearerToken();
    // print("res121: " + _serverApiBaseUrl + route);
    return _callApi(_httpService
        .post(_serverApiBaseUrl + route, body: dataAsJson, headers: {
      'Content-Type': 'application/json',
      'Accept': '*/*',
      HttpHeaders.authorizationHeader: "Bearer $token"
    }));
  }

  @override
  Future<BackendResponse> postUnauthenticatedAPI(
      String route, String dataAsJson) async {
    await checkConnection();
    return _callApi(_httpService.post(_serverApiBaseUrl + route,
        body: dataAsJson, headers: {'Content-Type': 'application/json'}));
  }

  Future<void> checkConnection() async {
    if (!(await Injector.appInstance
        .getDependency<INetworkService>()
        .isHostAvailable(_homeUrl))) throw NetworkException();
  }

  @override
  Future<BackendResponse> deleteAuthenticatedAPI(
      String route, String id) async {
    await checkConnection();
    final token = await _secureStorage.readBearerToken();
    return _callApi(
        _httpService.delete(_serverApiBaseUrl + route + "/" + id, headers: {
      'Content-Type': 'application/json',
      'Accept': '*/*',
      HttpHeaders.authorizationHeader: "Bearer $token"
    }));
  }
}
