import 'dart:convert';

import 'package:fhub/backend/helpers.dart';
import 'package:http/http.dart' as http;
import 'DebugHelper.dart';

class DataManager{
  static int ClientVersion = 2;

  static const String API_ENDPOINT = "http://vps.playpoolstudios.com/faucet/api/v2/";
  static Map<String,String> Settings = {};

  static List<dynamic> AllGames = [];
  static List<dynamic> FeaturedGames = [];
  static List<dynamic> LinkedGamesJson = [];
  static List<dynamic> NonLinkedGamesJson = [];

  static List<List<dynamic>> Challenges= [];

  static dynamic UserJson;

  static dynamic cryptoRates;
  static double currentEarnings =0;
  static Map<String, int> GamesEarnings = {};
  static Map<String, int> CryptoEarnings = {};


  static void Reset(){
    UserJson = LinkedGamesJson = NonLinkedGamesJson = Challenges = [];
    currentEarnings = 0;
    GamesEarnings = CryptoEarnings = {};
  }

  static Future<int> GetVersion() async{
    var response = (await http.post(Uri.parse('${API_ENDPOINT}get_version.php')));
    int v = -1;
    try{
      v = int.parse(response.body.toString());
    }catch(e){
      v=-1;
    }

    return v;
  }

  static Future<bool> Init() async{
    bool isSettingsDone = await GetSettings();
    bool isGamesDone = await GetGames();
    CalculateEarnings();
    StartGrabbing();
    return isSettingsDone && isGamesDone;
  }

  static void StartGrabbing() async{
    while(true){
      await Future.delayed(const Duration(minutes: 1));

      await GrabOnce();
    }
  }

  static Future<void> GrabOnce() async{
    await GetSettings();
    await GetGames();
    await GetChallenges();
    await GetUserData();
    CalculateEarnings();
  }
  static String username= "";
  static String password = "";

  static Future<int> GetUserData() async{
    var loginResponse = null;
    try {
      loginResponse = (await http.post(
          Uri.parse('${DataManager.API_ENDPOINT}get_userdata.php'),
          body: <String, String>{
            "username": username,
            "password": password
          }));
      Debug.LogError(loginResponse.body.toString());

      try{
        DataManager.UserJson = jsonDecode(loginResponse.body.toString());
        await DataManager.GetGamesProgress();
        return 0;
      }catch(e){
        return 5;
      }
    } catch (e) {
      Debug.LogError("Error while login $e");
    }

    return 1;
  }

  static Future<void> GetGamesProgress() async{
    FilterLinkedGames();
    await GetChallenges();

  }

  static void FilterLinkedGames(){
   Debug.Log("err044 : $UserJson");
      LinkedGamesJson = [];
      NonLinkedGamesJson = [];
      if (UserJson['linked_games']
          .toString()
          .length < 3) {
        NonLinkedGamesJson = AllGames;
        return;
      }
      List<Map<String, dynamic>> linkedGames = jsonDecode(
          UserJson['linked_games']).cast<Map<String, dynamic>>();

      AllGames.forEach((element) {
        bool foundLink = false;
        for (var linkedGame in linkedGames) {
          int gid = linkedGame["game_id"];
          int id = int.parse(element['id']);
          if (gid == id) {
            LinkedGamesJson.add(element);
            foundLink = true;
            break;
          }
        }

        if (!foundLink) {
          NonLinkedGamesJson.add(element);
        }
      });

  }

  static Future<bool> GetSettings() async{
    try {
      var response = (await http.post(Uri.parse('${API_ENDPOINT}get_settings.php')));

      Debug.LogResponse("settings: ${response.body}");

      List jsonList = jsonDecode(response.body.toString());
      jsonList.forEach((jsonItem) {
        Settings[jsonItem['id']] = jsonItem['value'];
      });

      return true;
    } catch (e) {
      Debug.LogError("Error while gettings settings :  $e");
      return false;
    }
  }

  static double MinWdAmount(){
    return double.parse(GetSettingById("min_wd_amount"));
  }

  static String GetSettingById(String id){
    String val = "";
    Settings.forEach((key, value) {
      if(key == id){
        val = value;
      }
    });
    return val;
  }
  
  static Future<bool>GetGames() async{
    try {
      var response = (await http.post(Uri.parse('${API_ENDPOINT}get_games.php')));

      Debug.LogResponse("Games: ${response.body}");
      AllGames=[];
      FeaturedGames = [];
      List<String> games = response.body.toString().split("<td>");
      List<String> featuredGames = Settings["featured_games"].toString().split(',');
      games.forEach((game) {
        dynamic Json = jsonDecode(game);
        String id = Json['id'];
        AllGames.add(Json);
        print(Json);

        if(featuredGames.contains(id)){
          FeaturedGames.add(Json);
        }
      });
      
      return true;
    } catch (e) {
      Debug.LogError("Error while loading games :  $e");
      
      return false;
    }
  }

  static Future<bool> GetChallenges() async{
    var response = null;

    List<List<dynamic>> _Challenges = [];
    double _currentEarnings = 0;
    for (var value in LinkedGamesJson) {
      try {
        Debug.Log("game_code : ${value['code']}, id: ${UserJson['id']}");
        response = (await http.post(
            Uri.parse('${API_ENDPOINT}get_challenges.php'),
            body: <String, String>{
              "game_code": value['code'],
              "id": UserJson['id']
            }));
        Debug.Log("Challenges response: " +response.body.toString());
        List<dynamic> newChallenges = jsonDecode(response.body.toString());

        _Challenges.add(newChallenges);
      } catch (e) {
        Debug.LogError("Error while fetching challenges $e");
        return false;
      }
    }

    Challenges = _Challenges;
    return true;
  }



  static Future<void> CalculateEarnings() async{
    Debug.Log("Going to calculate earnings from games");
    while(UserJson == null){
      await Future.delayed(const Duration(seconds: 1));
    }
    try{
      if(UserJson == null){Debug.LogError("User json is null, Abort calculating earnings");return;}
      Map<String, dynamic> earningsObj = jsonDecode(UserJson['earnings']);
      var cryptoValuesResponse = await http.get(Uri.parse('http://vps.playpoolstudios.com:2009/'));
      dynamic cryptoValues = jsonDecode(cryptoValuesResponse.body.toString());
      cryptoRates = cryptoValues;
      Debug.Log(cryptoValues);
      currentEarnings=0;
      Map<String, int> _ThisSeasonCryptoEarnings = {};
      Map<String, int> _ThisSeasonGamesEarnings = {};

      earningsObj.forEach((key, _earnings) {
        int earnings;
        try{
          earnings = _earnings;
        }catch(e){
          earnings = int.parse(_earnings);
        }
        Debug.Log("$key : $earnings");
        dynamic gameData = Helpers.GetGameFromCode(key);
        _ThisSeasonCryptoEarnings.update(gameData['coin'], (value) => earnings, ifAbsent: ()=> earnings);
        _ThisSeasonGamesEarnings.update(key, (value) => earnings, ifAbsent: ()=> earnings);

        double rewardInDollars = double.parse(cryptoValues[gameData['coin']]) * (0.00000001) * earnings;
        Debug.Log(rewardInDollars);
        currentEarnings += rewardInDollars;
      });
      currentEarnings = currentEarnings;
      CryptoEarnings = _ThisSeasonCryptoEarnings;
      GamesEarnings = _ThisSeasonGamesEarnings;
      Debug.Log(_ThisSeasonCryptoEarnings);

      // return true;
    }catch(e){
      Debug.LogError("Error at calculating earnings from games $e");

      // return false;
    }
  }

  static Future<void> ClaimChallenge(dynamic challengeData) async{
    Map<String,String> body = <String, String>{
      "game_code": challengeData['game'],
      "id": UserJson['id'],
      "challenge_id" : challengeData['id']
    };
    var response = (await http.post(
        Uri.parse('${API_ENDPOINT}claim_challenge.php'),
        body: body));
    Debug.Log("Challenges response: " +response.body.toString());
    try{
      dynamic newEarnings = jsonDecode(response.body.toString());
      UserJson['earnings'] = response.body.toString();
      await GetChallenges();
      CalculateEarnings();
    }catch(e){
      Debug.LogError("Error claiming challenge : ${challengeData}");
      Debug.LogError(body);
      Debug.LogError(e);
    }
  }

  static Future<String> SetWdAddress(String newAddress) async{
    String prevAddress = UserJson['wd_address'] ?? "";
    Map<String,String> body = <String, String>{
      "id": UserJson['id'],
      "newAddress" : newAddress
    };
    var response = (await http.post(
        Uri.parse('${API_ENDPOINT}set_wd_address.php'),
        body: body));
    Debug.Log("Set WD Address response: " +response.body.toString());
    UserJson['wd_address'] =(response.body.toString() == newAddress) ? newAddress : prevAddress;

    return (response.body.toString());
  }

  static Future<bool> RequestWd(String coin) async{

    Map<String,String> body = <String, String>{
      "id": UserJson['id'],
      "username" : UserJson['name'],
      "coin": coin
    };
    var response = (await http.post(
    Uri.parse('${API_ENDPOINT}request_wd.php'),
        body: body));
    Debug.Log("Request WD response: " +response.body.toString());

    if(response.body.toString().contains("{")){
      UserJson['earnings'] =(response.body.toString());
      await CalculateEarnings();
      return true;
    }else{
      return false;
    }
  }

  static Future<int> Review() async{
    var loginResponse = null;
    try {
      loginResponse = (await http.post(
          Uri.parse('${DataManager.API_ENDPOINT}review.php'),
          body: <String, String>{
            "username": username,
            "password": password
          }));
      Debug.LogResponse(loginResponse.body.toString(),src: "review.php");

      try{
        DataManager.UserJson = jsonDecode(loginResponse.body.toString());
        await DataManager.GetGamesProgress();
        return 0;
      }catch(e){
        return 5;
      }
    } catch (e) {
      Debug.LogError("Error while review $e");
    }

    return 1;
  }


  static Future<List<dynamic>> GetWithdrawalHistory() async{
    Map<String,String> body = <String, String>{
      "id": UserJson['id']
    };
    var response = (await http.post(
        Uri.parse('${API_ENDPOINT}get_wd_history.php'),
        body: body));
    Debug.Log("wd history response: " +response.body.toString());

    return jsonDecode(response.body.toString());
  }

}