using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class GameManagerScript : MonoBehaviour {

    private int questionTimer;
    private string gameMode;

    private int neededForWin;

    private String gameStatus;

    public Database db;
    public OnlineDatabase odb;
    StatsScript statsScript;
    ScrollViewScript scrollViewScript;
     
     [SerializeField] GameObject NewQuestionCard;
     [SerializeField] GameObject AnswerLine;
     [SerializeField] GameObject AnswerLineQuestionCard;
     [SerializeField] GameObject DropZonePrefab;
     [SerializeField] GameObject TimerPanel;
    public string GameMode { get => gameMode; set => gameMode = value; }
    public int GameId { get; internal set; }

    public int QuestionTimer { get => questionTimer; set => questionTimer = value; }
    public int NeededForWin { get => neededForWin; set => neededForWin = value; }
    public string GameStatus { get => gameStatus; set => gameStatus = value; }

    static string currentPlayer;

    private bool newQuestionCardMoving = false;

    [SerializeField] float movementSpeed = 1.0f;

    List<KeyValuePair<string, int>> players;

    // Start is called before the first frame update
    void Start() {
        GameId = PlayerPrefs.GetInt(Constants.GAME_ID);
        GameMode = PlayerPrefs.GetString(Constants.GAME_MODE);
        QuestionTimer = PlayerPrefs.GetInt(Constants.GAME_QUESTION_TIMER);
        NeededForWin = PlayerPrefs.GetInt(Constants.GAME_TO_WIN);

        if (GameMode.Equals(Constants.LOCAL)) {
            db = Database.Instance;
            db.SetLocalOrOnline(GameMode);
            db.SetLastPlayedDate(GameId);
        } else if (GameMode.Equals(Constants.ONLINE)) {
            odb = OnlineDatabase.Instance;
            odb.SetLastPlayedDate(GameId);
        }
        GameObject statsPanelObject = GameObject.Find("StatsPanel");
        if (statsPanelObject != null) {
            statsScript = statsPanelObject.GetComponent<StatsScript>();
        }

        GameObject answerLineObject = GameObject.FindGameObjectWithTag("AnswerLine");
        
        if (answerLineObject != null) {
            scrollViewScript = answerLineObject.transform.parent.parent.GetComponent<ScrollViewScript>();
        }
        
        if (SceneManager.GetActiveScene().name.Equals(Constants.SCENE_NAR_KAMPEN)) {
            currentPlayer = Database.Instance.GetCurrentPlayer(GameId, GameMode);
        }
    }

    public void StartTimer()
    {
        TimerPanel.GetComponentInChildren<TimerScript>().ResetTimer();
        TimerPanel.GetComponentInChildren<TimerScript>().StartTimer();
    }

    public void StopTimer() {
        TimerScript timerScript = TimerPanel.GetComponentInChildren<TimerScript>();
        timerScript.StopTimer();
        timerScript.ResetTimer();
    }

    void Awake()
    {
        if (SceneManager.GetActiveScene().name.Equals(Constants.SCENE_NAR_KAMPEN)) {
            GameId = PlayerPrefs.GetInt(Constants.GAME_ID);
            GameMode = PlayerPrefs.GetString(Constants.GAME_MODE);
            if (Database.Instance.GetRoundValue(GameId, GameMode) == 1) {
                StartCoroutine(startAnimation());
            }
        }
    }

    private IEnumerator startAnimation()
    {

        NewQuestionCardController newQuestionCardController = NewQuestionCard.GetComponent<NewQuestionCardController>();
        newQuestionCardController.RotateCard();

        while (!newQuestionCardController.getRotationDone())
        {
            yield return new WaitForSeconds(0.1f);
        }

        //NewQuestionCard.transform.position = AnswerLine.transform.position;
        StartCoroutine(MoveCardToAnswerLine());

        while (newQuestionCardMoving) {
            yield return new WaitForSeconds(0.1f);
        }

        RectTransform newQuestionRect = GameObject.Find("NewQuestion").GetComponent<RectTransform>();

        NewQuestionData newQuestionData = NewQuestionCard.transform.parent.parent.GetComponent<NewQuestionsPanel>().QuestionData;
        GameObject go = Instantiate(AnswerLineQuestionCard, Vector3.zero, Quaternion.identity);
        AnswerLineQuestionCard firstAnswerLineQuestion = go.GetComponent<AnswerLineQuestionCard>();
        firstAnswerLineQuestion.SetAnswerText(newQuestionData.Answer);
        firstAnswerLineQuestion.SetQuestionText(newQuestionData.Question);
        firstAnswerLineQuestion.SetId(newQuestionData.Id);
        firstAnswerLineQuestion.SetQuestionSafe();
        firstAnswerLineQuestion.SetBackCategoryText(newQuestionData.CategoryName);
        firstAnswerLineQuestion.SetQuestionCategoryColor(newQuestionData.CategoryColor);

        firstAnswerLineQuestion.GetComponent<LayoutElement>().preferredHeight = newQuestionRect.rect.height;
        firstAnswerLineQuestion.GetComponent<LayoutElement>().preferredWidth = newQuestionRect.rect.width;
        firstAnswerLineQuestion.transform.SetParent(AnswerLine.transform);
        firstAnswerLineQuestion.transform.SetSiblingIndex(0);
        firstAnswerLineQuestion.transform.localScale = new Vector3(1,1,1);

        CreateLeftSpacer(newQuestionRect.rect.width);
        CreateRightSpacer(newQuestionRect.rect.width);

        NewQuestionCard.GetComponent<NewQuestionCardController>().GenerateNewQuestion();
        // Destroy(NewQuestionCard.gameObject);
        StopTimer();
    }

    internal void CheckWin(List<QuestionCard> answerLine)
    {
        if (answerLine.Count == NeededForWin) {
            GenericDialog dialog = GenericDialog.Instance();
            dialog.SetTitle(LocalizationManager.Instance.GetText("WINNER_DIALOG_TITLE"));
            string message = LocalizationManager.Instance.GetText("WINNER_DIALOG_MESSAGE");
            dialog.SetMessage(String.Format(message, NeededForWin, 
                Database.Instance.GetQuestionsLost(GameId, currentPlayer, GameMode), 
                Database.Instance.GetRoundValue(GameId, GameMode)));
            dialog.SetOnAccept(LocalizationManager.Instance.GetText("OK"), () => {
                GameStatus = "FINISHED";
                Database.Instance.SetGameFinished(GameId, GameMode);
                scrollViewScript.SetAllQuestionsLocked(true);
                
                if (GameMode.Equals(Constants.ONLINE)) {
                    OnlineDatabase.Instance.SendGameOverMessage(GameId, players, currentPlayer, Database.Instance.GetRoundValue(GameId, GameMode));
                }

                dialog.Hide();
            });
            dialog.SetOnDecline("", () => dialog.Hide());
            dialog.Show();
        }
    }

    internal void RemoveUnlockedQuestions()
    {
        if (scrollViewScript == null) {
            scrollViewScript = GameObject.FindGameObjectWithTag("AnswerLine").transform.parent.parent.GetComponent<ScrollViewScript>();
        }
        scrollViewScript.RemoveUnlockedQuestions();
    }

    internal int GetUnlockedQuestionsCount() {
                if (scrollViewScript == null) {
            scrollViewScript = GameObject.FindGameObjectWithTag("AnswerLine").transform.parent.parent.GetComponent<ScrollViewScript>();
        }
        return scrollViewScript.GetUnlockedQuestionCount();
    }

    private void CreateLeftSpacer(float width)
    {
        GameObject newSpacerLeft = Instantiate(DropZonePrefab);     
        newSpacerLeft.GetComponent<LayoutElement>().preferredWidth = width;
        newSpacerLeft.name = "LeftDropZone";
        newSpacerLeft.GetComponent<NewDropZoneScript>().LeftmostSpacer = true;
        newSpacerLeft.transform.SetParent(AnswerLine.transform);
        newSpacerLeft.transform.SetAsFirstSibling();
        newSpacerLeft.transform.localScale = new Vector3(1,1,1);
    }

    private void CreateRightSpacer(float width)
    {
        GameObject newSpacerRight = Instantiate(DropZonePrefab);     
        newSpacerRight.GetComponent<LayoutElement>().preferredWidth = width;
        newSpacerRight.name = "RightDropZone";
        newSpacerRight.GetComponent<NewDropZoneScript>().RightmostSpacer = true;
        newSpacerRight.transform.SetParent(AnswerLine.transform);
        newSpacerRight.transform.SetAsLastSibling();
        newSpacerRight.transform.localScale = new Vector3(1,1,1);
    }

    private IEnumerator MoveCardToAnswerLine()
    {
        newQuestionCardMoving = true;
        Vector3 alPosition = AnswerLine.transform.position;
        float t = 0f;
        while (alPosition != NewQuestionCard.transform.position)
        {
            t += Time.deltaTime / 10.0f;
            float step = movementSpeed * Time.deltaTime;
            NewQuestionCard.transform.position = Vector3.Lerp(NewQuestionCard.transform.position, AnswerLine.transform.position, t);
            if (Vector3.Distance(NewQuestionCard.transform.position, AnswerLine.transform.position) < 0.01f)
            {
                NewQuestionCard.transform.position = AnswerLine.transform.position;
            }
            yield return null;
        }
        newQuestionCardMoving = false;
    }

    private List<KeyValuePair<string,int>> GetPlayersForGame() {
        players = db.GetPlayersForGame(GameId, GameMode);
        return players;
    }

    public void UpdateQuestiosLost(int questionsLost, string playerName) {
        db.SetQuestionsLost(GameId, playerName, questionsLost);
    }

    public void UpdateQuestionsInAnswerLine(string playerName, int count) {
        
    }

    public List<KeyValuePair<string, int>> GetPlayers() {
        if (players == null) {
            players = GetPlayersForGame();
        }
        return players;
    }

    public void NextRound() {
        StopTimer();
        NewQuestionCard.transform.GetComponent<NewQuestionCardController>().GenerateNewQuestion();
        if (scrollViewScript == null) {
            scrollViewScript = GameObject.FindGameObjectWithTag("AnswerLine").transform.parent.parent.GetComponent<ScrollViewScript>();
        }
        scrollViewScript.SetAllQuestionsLocked(true);
        scrollViewScript.RemoveEverythingFromAnswerline();
        NextPlayer();
    }

    private void NextPlayer() {
        Database.Instance.IncreasePlayerRound(GameId, currentPlayer);
        if (GameMode.Equals(Constants.ONLINE)) {
            statsScript.IncreaseRoundValue();
        }

        for (int i = 0; i < players.Count; i++) {
            if (players[i].Key.Equals(currentPlayer, StringComparison.InvariantCultureIgnoreCase)) {
                if (i + 1 < players.Count) {
                    currentPlayer = players[i + 1].Key;
                    break;
                } else {
                    currentPlayer = players[0].Key;
                    if (GameMode.Equals(Constants.LOCAL)) {
                        statsScript.IncreaseRoundValue();
                    }
                    break;
                }
            }
        }
        
        GenericDialog dialog = GenericDialog.Instance();
        dialog.SetTitle(LocalizationManager.Instance.GetText("NEXT_PLAYER_DIALOG_TITLE"));
        string message = LocalizationManager.Instance.GetText("NEXT_PLAYER_DIALOG_MESSAGE");
        dialog.SetMessage(String.Format(message, currentPlayer));
        dialog.SetOnAccept(LocalizationManager.Instance.GetText("OK"), () => {
            scrollViewScript.RemoveEverythingFromAnswerline();
            List<NewQuestionData> questions = new List<NewQuestionData>();
            if (GameMode.Equals(Constants.ONLINE)) {
                questions = Database.Instance.GetPlayerQuestions(GameId, Database.Instance.GetSignedInUser().Value, gameMode);
            } else {
                questions = Database.Instance.GetPlayerQuestions(GameId, currentPlayer, gameMode);
            }
            scrollViewScript.SetQuestionsInAnswerLine(questions);

            statsScript.SetQuestionsLost(Database.Instance.GetQuestionsLost(GameId, currentPlayer, GameMode));

            statsScript.MakeBold(currentPlayer);
            Database.Instance.SetCurrentPlayer(GameId, currentPlayer, GameMode);

            InformationPanelScript ips = GameObject.Find("InformationPanel").GetComponent<InformationPanelScript>();

            if (GameMode.Equals(Constants.ONLINE)) {
                OnlineDatabase.Instance.SendNextPlayerMessage(GameId, currentPlayer);
            }
            dialog.Hide();
        });
        dialog.SetOnDecline("", () => dialog.Hide());
        dialog.Show();
    }

    public static string GetCurrentPlayer() {
        return currentPlayer;
    }

    public void QuitApplication() {
        Application.Quit();
    }

    public String getLanguage() {

        return "Svenska";
    }
}
