using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Mono.Data.Sqlite;
using System.Data;
using System;
using UnityEngine.Networking;
using System.IO;

public class OnlineDatabase : MonoBehaviour {
    private const string onlineQuestionsUrl = "nordh.xyz/narKampen/dbFiles/Question.php";
    private const string serverUrl = "nordh.xyz/narKampen/dbFiles/";
    string gameMode;
    int winAmount = -1;

    public GameObject questionCardPrefab;

    private static OnlineDatabase instance;
    public static OnlineDatabase Instance { get { return instance; } }

    private void Awake() {
        if (instance == null) {
            instance = this;
        }
    }

    internal List<CategoryPanel.Category> GetCategories(List<CategoryPanel.Category> list) {
        string response = CallOnlineDatabaseWithResponse("Categories.php", null);

        response = "{\"categoryList\" :  " + response + " }";

        Categories categories = new Categories();
        JsonUtility.FromJsonOverwrite(response, categories);

        foreach (Category c in categories.categoryList) {
            CategoryPanel.Category cat = new CategoryPanel.Category();

            cat.color = new Color32((byte)c.r, (byte)c.g, (byte)c.b, (byte)c.a);
            cat.name = c.name;
            cat.id = c.id;

            list.Add(cat);
        }
        return list;
    }

    internal void SetupNewOnlineGame(int limitPerQuestion, int limitPerPlayer, int toWin, List<InviteSearchResult> inviteUsers) {
        List<int> playerIds = new List<int>();
        inviteUsers.ForEach(i => playerIds.Add(i.GetId()));
        int currentUser = Database.Instance.GetSignedInUser().Key;
        playerIds.Add(currentUser);

        var form = new WWWForm();
        form.AddField("currentUser", currentUser);
        form.AddField("winNumber", toWin);
        form.AddField("limitPerQuestion", limitPerQuestion);
        form.AddField("limitPerPlayer", limitPerPlayer);
        form.AddField("playerIds", String.Join(",", playerIds));

        string response = CallOnlineDatabaseWithResponse("NewOnlineGame.php", form);

        if (!response.Equals("")) {
            Debug.Log(response);
        }
    }

    [Serializable]
    public class Question {
        public string question;
        public string answer;
        public string id;
        public string category;
        public int r;
        public int g;
        public int b;
        public int a;
    }

    [Serializable]
    public class Questions {
        public List<Question> questionsList = new List<Question>();
    }

    [Serializable]
    public class PlayerInfo {
        public string username;
        public string status;
    }

    [Serializable]
    public class PlayerInfos {
        public List<PlayerInfo> playerInfoList = new List<PlayerInfo>();
    }

    [Serializable]
    public class GamePlayerInfo {
        public string username;
        public string userLockedQuestions;
    }

    [Serializable]
    public class GamePlayerInfos {
        public List<GamePlayerInfo> gamePlayerInfoList = new List<GamePlayerInfo>();
    }



    [Serializable]
    public class Category {
        public int r;
        public int g;
        public int b;
        public int a;
        public int id;
        public string name;
    }

    [Serializable]
    public class Categories {
        public List<Category> categoryList = new List<Category>();
    }

    [Serializable]
    public class OnlineGame {
        public string id;
        public string winNumber;
        public string answerTimer;
        public string roundTimeLimit;
        public string currentPlayer;
        public string round;
        public string startDate;
        public string LastPlayedDate;
        public string finishedDate;
        public string status;
    }

    [Serializable]
    public class OnlineGames {
        public List<OnlineGame> onlineGamesList = new List<OnlineGame>();
    }

    [Serializable]
    public class UserName {
        public string id;
        public string username;
    }

    [Serializable]
    public class UserNames {
        public List<UserName> usernamesList = new List<UserName>();
    }

    private void CallDatabase(string filename, WWWForm formData) {
        string postUrl = serverUrl + filename;

        UnityWebRequest www = UnityWebRequest.Post(postUrl, formData);
        www.SendWebRequest();

        if (www.isNetworkError || www.isHttpError) {
            Debug.Log(www.error);
        } else {
            while (!www.isDone) {
            }
        }
    }

    private string CallOnlineDatabaseWithResponse(string filename, WWWForm formData) {
        string postUrl = serverUrl + filename;

        UnityWebRequest www = UnityWebRequest.Post(postUrl, formData);
        www.SendWebRequest();

        if (www.isNetworkError || www.isHttpError) {
            Debug.Log(www.error);
        } else {
            while (!www.isDone) {
            }
        }

        return www.downloadHandler.text;
    }

    string questionString = "";
    string answerString = "";
    string idString = "";
    string categoryString = "";

    public string QuestionString { get => questionString; set => questionString = value; }


    private void Start() {
        if (instance == null) {
            instance = this;
        }
    }

    internal void SetLastPlayedDate(int gameId) {

        WWWForm form = new WWWForm();
        form.AddField("gameId", gameId);
        form.AddField("f", "SetLastPlayed");
        string response = CallOnlineDatabaseWithResponse("OnlineGames.php", form);

        if (!response.Equals("")) {
            Debug.Log(response);
        }
    }

    internal void DeclineOnlineGame(string userName, int gameId) {
        WWWForm formData = new WWWForm();
        formData.AddField("userId", -1);
        formData.AddField("f", "decline");
        formData.AddField("gameId", gameId);
        formData.AddField("userName", userName);

        CallDatabase("OnlineGames.php", formData);
    }

    internal void AcceptOnlineGame(string userName, int gameId) {
        WWWForm formData = new WWWForm();
        formData.AddField("userId", -1);
        formData.AddField("f", "accept");
        formData.AddField("gameId", gameId);
        formData.AddField("userName", userName);

        string response = CallOnlineDatabaseWithResponse("OnlineGames.php", formData);
        if (!response.Equals("")) {
            Debug.Log(response);
        }
    }

    internal List<OnlineGameScript> GetOnlineGames(int userId, string userName, GameObject prefab) {

        WWWForm formData = new WWWForm();
        formData.AddField("userId", userId);
        formData.AddField("f", "list");
        formData.AddField("gameId", -1);
        formData.AddField("userName", userName);

        string response = CallOnlineDatabaseWithResponse("OnlineGames.php", formData);

        if (response.Equals("No games found for user") || response.Equals("")) {
            return null;
        }

        response = "{\"onlineGamesList\" :  " + response + " }";

        OnlineGames og = new OnlineGames();
        JsonUtility.FromJsonOverwrite(response, og);

        GameObject onlineGameObject;
        OnlineGameScript ogs = null;
        List<OnlineGameScript> games = new List<OnlineGameScript>();
        foreach (OnlineGame game in og.onlineGamesList) {
            onlineGameObject = Instantiate(prefab, new Vector2(0, 0), Quaternion.identity) as GameObject;
            ogs = onlineGameObject.GetComponent<OnlineGameScript>();
            ogs.CurrentPlayer = game.currentPlayer;
            ogs.SetGameStatus(game.status);
            Int32.TryParse(game.id, out int gameId);
            List<KeyValuePair<string, string>> playerInfos = GetGameInfo(gameId);
            if (game.status.Equals("PENDING")) {
                string extraInfo = "";
                foreach (KeyValuePair<string, string> s in playerInfos) {
                    if (s.Value.Equals("WAITING") && s.Key.Equals(userName, StringComparison.InvariantCultureIgnoreCase)) {
                        ogs.SetGameStatus("INVITED");
                        extraInfo += s.Key + ",";
                    } else if (s.Value.EndsWith("WAITING")) {
                        extraInfo += s.Key + ",";
                    }
                }
                extraInfo = extraInfo.TrimEnd(',');
                ogs.SetGameStatusText(extraInfo);

            } else if (game.status.Equals("OTHERS_TURN")) { // Wont work
                ogs.SetGameStatusText(game.currentPlayer);
            } else if (game.status.Equals("ACTIVE")) {
                ogs.SetGameStatusText(game.currentPlayer);
            } else {
                ogs.SetGameStatusText();
            }

            ogs.SetId(game.id);
            ogs.SetWinNumber(game.winNumber);
            ogs.SetAnswerTimer(game.answerTimer);
            ogs.SetRoundTimeLimit(game.roundTimeLimit);
            ogs.SetRound(game.round);
            ogs.StartDate = game.startDate;

            games.Add(ogs);
            ogs.PlayerInfos = playerInfos;
        }

        return games;
    }

    internal List<KeyValuePair<string, string>> GetGameInfo(int gameId) {
        List<KeyValuePair<string, string>> returnList = new List<KeyValuePair<string, string>>();

        WWWForm form = new WWWForm();
        form.AddField("f", "GetGameInfo");
        form.AddField("gameId", gameId);

        string response = CallOnlineDatabaseWithResponse("OnlineGameInfo.php", form);

        response = "{\"playerInfoList\" : " + response + " }";
        PlayerInfos pi = new PlayerInfos();
        JsonUtility.FromJsonOverwrite(response, pi);

        foreach (PlayerInfo p in pi.playerInfoList) {
            KeyValuePair<string, string> player = new KeyValuePair<string, string>(p.username, p.status);
            returnList.Add(player);
        }

        return returnList;
    }

    internal void SetQuestionsLost(int gameId, string playerName, int questionsLost) {
        WWWForm form = new WWWForm();
        form.AddField("f", "SetQuestionsLost");
        form.AddField("questionsLost", questionsLost);
        form.AddField("userName", playerName);
        form.AddField("gameId", gameId);

        string response = CallOnlineDatabaseWithResponse("OnlineGames.php", form);

        if (!response.Equals("")) {
            Debug.Log(response);
        }
    }

    internal void RemoveGame(int gameId) {
        WWWForm form = new WWWForm();
        form.AddField("f", "DeleteGame");
        form.AddField("gameId", gameId);

        string response = CallOnlineDatabaseWithResponse("OnlineGames.php", form);

        if (!response.Equals("")) {
            Debug.Log(response);
        }
    }

    public string GetCurrentPlayer(int gameId) {
        WWWForm form = new WWWForm();
        form.AddField("f", "CurrentPlayer");
        form.AddField("gameId", gameId);

        string response = CallOnlineDatabaseWithResponse("OnlineGames.php", form);
        if (response.Equals("")) {
            Debug.Log("Something wrong with current player for game with id: " + gameId);
        }
        return response;
    }

    public void SetCurrentPlayer(int gameId, string currentPlayer) {
        WWWForm form = new WWWForm();
        form.AddField("f", "SetCurrentPlayer");
        form.AddField("gameId", gameId);
        form.AddField("currentPlayer", currentPlayer);

        string response = CallOnlineDatabaseWithResponse("OnlineGames.php", form);

        if (!response.Equals("")) {
            Debug.Log(response);
        }
        
    }

    internal int GetPlayerPoints(int gameId, string playerName) {
        WWWForm form = new WWWForm();
        form.AddField("f", "GetPlayerPoints");
        form.AddField("gameId", gameId);
        form.AddField("userName", playerName);

        string response = CallOnlineDatabaseWithResponse("OnlineGames.php", form);
        if (response.Equals("")) {
            Debug.Log("Something wrong with current player for game with id: " + gameId);
        }
        Int32.TryParse(response, out int playerPoints);
        return playerPoints;
    }

    internal void SetFinishedDate(int gameId, string finishedDate) {
        WWWForm form = new WWWForm();
        form.AddField("f", "SetFinishedDate");
        form.AddField("gameId", gameId);
        form.AddField("finishedDate", finishedDate);

        string response = CallOnlineDatabaseWithResponse("OnlineGames.php", form);

        if (!response.Equals("")) {
            Debug.Log(response);
        }
    }

    internal void SetRoundValue(int gameId, int round) {
        WWWForm form = new WWWForm();
        form.AddField("f", "SetRound");
        form.AddField("gameId", gameId);
        form.AddField("round", round);

        string response = CallOnlineDatabaseWithResponse("OnlineGames.php", form);

        if (!response.Equals("")) {
            Debug.Log(response);
        }
    }

    internal int GetRoundValue(int gameId) {
        WWWForm form = new WWWForm();
        form.AddField("f", "GetRound");
        form.AddField("gameId", gameId);

        string response = CallOnlineDatabaseWithResponse("OnlineGames.php", form);
        if (response.Equals("")) {
            Debug.Log("Something wrong with getting round for game with id: " + gameId);
        }
        Int32.TryParse(response, out int round);
        return round;
    }

    internal List<KeyValuePair<string, int>> GetPlayersForGame(int gameId) {
        WWWForm form = new WWWForm();
        form.AddField("f", "GetPlayers");
        form.AddField("gameId", gameId);

        string response = CallOnlineDatabaseWithResponse("OnlineGames.php", form);
        if (response.Equals("")) {
            Debug.Log("Something wrong with getting players from game with id: " + gameId);
        }

        response = response = "{\"gamePlayerInfoList\" : " + response + " }";
        GamePlayerInfos gpi = new GamePlayerInfos();
        JsonUtility.FromJsonOverwrite(response, gpi);

        List<KeyValuePair<string, int>> returnList = new List<KeyValuePair<string, int>>();
        foreach (GamePlayerInfo p in gpi.gamePlayerInfoList) {
            Int32.TryParse(p.userLockedQuestions, out int points);
            KeyValuePair<string, int> player = new KeyValuePair<string, int>(p.username, points);
            returnList.Add(player);
        }

        return returnList;
    }

    public string AnswerString { get => answerString; set => answerString = value; }
    public string IdString { get => idString; set => idString = value; }
    public string CategoryString { get => categoryString; set => categoryString = value; }

    internal int GetQuestionsLost(int gameId, string playerName) {
        WWWForm form = new WWWForm();
        form.AddField("f", "GetQuestionsLost");
        form.AddField("userName", playerName);
        form.AddField("gameId", gameId);

        string response = CallOnlineDatabaseWithResponse("OnlineGames.php", form);
        if (response.Equals("")) {
            Debug.Log("Something wrong with getting questions lost from game with id: " + gameId + " and playername " + playerName);
        }
        Int32.TryParse(response, out int questionsLost);
        return questionsLost;
    }

    internal int GetWinCondition(int gameId) {
        if (winAmount == -1) {
            WWWForm form = new WWWForm();
            form.AddField("gameId", gameId);
            form.AddField("f", "GetWinCondition");

            string response = CallOnlineDatabaseWithResponse("OnlineGames.php", form);

            Int32.TryParse(response, out this.winAmount);

        }
        return this.winAmount;
    }

    public NewQuestion GetNewQuestion(List<int> userAnsweredQuestions, string userName) {
        int gameId = GameObject.Find("GameManager").GetComponent<GameManagerScript>().GameId;

        Question q = GetQuestionData(false);
        NewQuestion nq = NewQuestion.Instance();
        nq.questionString = q.question;
        nq.answerString = q.answer;
        nq.categoryString = q.category;
        nq.idString = q.id;
        Color32 questionCategoryColor = new Color32((byte)q.r, (byte)q.g, (byte)q.b, (byte)q.a);
        nq.SetQuestionCategoryColor(questionCategoryColor);

        return nq;
    }

    public void SavePlayersQuestion(List<int> questionsToSave, string playerNameValue, int gameId) {
        WWWForm form = new WWWForm();
        form.AddField("f", "SavePlayerQuestions");
        form.AddField("gameId", gameId);
        form.AddField("questionsToSave", String.Join(",",questionsToSave));
        form.AddField("userName", playerNameValue);

        string response = CallOnlineDatabaseWithResponse("OnlineGames.php", form);

        if (!response.Equals("")) {
            Debug.Log(response);
        }
    }

    public List<QuestionCard> GetPlayerQuestions(int gameId, string playerName) {
        List<QuestionCard> questions = new List<QuestionCard>();
        WWWForm form = new WWWForm();
        form.AddField("f", "PlayerQuestions");
        form.AddField("gameId", gameId);
        form.AddField("userName", playerName);

        string response = CallOnlineDatabaseWithResponse("OnlineGameInfo.php", form);
        response = "{\"questionsList\" : " + response + "}";
        
        Questions ql = new Questions();

        JsonUtility.FromJsonOverwrite(response, ql);

        foreach (Question q in ql.questionsList) {
            GameObject question = Instantiate(questionCardPrefab, new Vector2(0, 0), Quaternion.identity) as GameObject;
            QuestionCard qc = question.GetComponent<QuestionCard>();

            qc.SetAnswerText(q.answer);
            qc.SetQuestionText(q.question);
            qc.idString = q.id;

            Color32 questionCategoryColor = new Color32((byte)q.r, (byte)q.g, (byte)q.b, (byte)q.a);
            qc.SetQuestionCategoryColor(questionCategoryColor);

            questions.Add(qc);
        }
        
        return questions;
    }

    private Question GetQuestionData(bool showAnswer) {
        WWWForm form = new WWWForm();

        string response = CallOnlineDatabaseWithResponse("Question.php", form);
        
        // Show result

        response = "{\"questionsList\" : [ " + response + " ]}";

        Questions qe = new Questions();
        JsonUtility.FromJsonOverwrite(response, qe);
        
        return qe.questionsList[0];
    }

    public List<UserName> GetUsersToInvite(string searchString) {
        string postUrl = "nordh.xyz/narKampen/dbFiles/PlayerSearch.php?";
        postUrl += "search=" + UnityWebRequest.EscapeURL(searchString);


        UserNames uNames = new UserNames();
        UnityWebRequest www = UnityWebRequest.Get(postUrl);
        www.SendWebRequest();

        if (www.isNetworkError || www.isHttpError) {
            Debug.Log(www.error);
        } else {
            while (!www.isDone) {
            }
            // Show result
            string jsonData = www.downloadHandler.text;

            if (!jsonData.Equals("")) {
                jsonData = "{\"usernamesList\" :  " + jsonData + " }";

                JsonUtility.FromJsonOverwrite(jsonData, uNames);
            }
        }
        // TODO handle empty
        return uNames.usernamesList;
    }

}
