using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEngine;

[Serializable]
[JsonObject]
public class Room
{
    public string code;

    [JsonConverter(typeof(ArrayToDictionaryConverter<Question>))]
    public Dictionary<int, Question> questions;
    public Dictionary<string, Player> players;
    public int currentQuestionId;
    public double creationDate;
    public int currentState;
    public string promptsLanguage;

    public Room(string _code)
    {
        code = _code;
        creationDate = DateTime.Now.ToOADate();
        players = new Dictionary<string, Player>();
        questions = new Dictionary<int, Question>();
        currentQuestionId = 0;
        currentState = 1; //default by PC
        promptsLanguage = "en";
    }

    public Room Copy()
    {
        Room newRoom = new Room(this.code)
        {
            questions = new Dictionary<int, Question>(this.questions),
            players = new Dictionary<string, Player>(this.players),
            currentQuestionId = this.currentQuestionId,
            creationDate = this.creationDate,
            currentState = this.currentState
        };

        return newRoom;
    }

    /// <summary>
    /// Return the only player with a specific ID
    /// </summary>
    /// <returns></returns>
    public Player GetPlayerById(string id)
    {
        return players[id];
    }

    /// <summary>
    /// Get the order of arrival of a player (the first player is 0, the last to connect is player.count-1)
    /// </summary>
    /// <param name="p">The player you want to know the position of</param>
    /// <returns>the position by arrival order</returns>
    public int GetPlayerOrder(Player p)
    {
        return GetOrderedPlayerList().FindIndex(x => x.id == p.id);
    }

    public List<Player> GetPlayerList()
    {
        return new List<Player>(players.Values);
    }

    /// <summary>
    /// return the list of player ordered by who joined first
    /// </summary>
    /// <returns></returns>
    public List<Player> GetOrderedPlayerList()
    {
        return players.Values.OrderBy(x => x.creationDate).ToList();
    }

    public List<Question> GetQuestionsByPlayer(Player player)
    {
        List<Question> playerQuestions = new();

        foreach (Question question in questions.Values.ToList())
        {
            foreach (Proposition proposition in question.propositions.Values.ToList())
            {
                if (proposition.owner.id == player.id)
                {
                    playerQuestions.Add(question);
                    break;
                }
            }
        }

        return playerQuestions;
    }

    /// <summary>
    /// Return all the propositions linked to a specific player.
    /// </summary>
    /// <param name="player"></param>
    /// <returns></returns>
    public List<Proposition> GetPropositionsForPlayer(Player player)
    {
        List<Proposition> playerPropositions = new();

        foreach (Question question in questions.Values.ToList())
        {
            foreach (Proposition proposition in question.propositions.Values.ToList())
            {
                if (proposition.owner.id == player.id)
                {
                    playerPropositions.Add(proposition);
                    break;
                }
            }
        }

        return playerPropositions;
    }

    /// <summary>
    /// Return the number of voters for a specific question
    /// </summary>
    /// <param name="_question"></param>
    /// <returns></returns>
    public int NumbersOfVotersForQuestion(Question _question)
    {
        int numberOfVoters = 0;

        foreach(Proposition proposition in _question.propositions.Values.ToList())
        {
            if (proposition.voters == null)
                continue;

            numberOfVoters += proposition.voters.Count;
        }

        return numberOfVoters;
    }
}

public class ArrayToDictionaryConverter<T> : JsonConverter<Dictionary<int, T>>
{
    public override Dictionary<int, T> ReadJson(JsonReader reader, Type objectType, Dictionary<int, T> existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartArray)
        {
            var jsonArray = JArray.Load(reader);
            var dictionary = new Dictionary<int, T>();

            for (int i = 0; i < jsonArray.Count; i++)
            {
                var item = jsonArray[i].ToObject<T>(serializer);
                dictionary.Add(i, item);
            }

            return dictionary;
        }

        return null;
    }

    public override void WriteJson(JsonWriter writer, Dictionary<int, T> value, JsonSerializer serializer)
    {
        if (value != null)
        {
            var jsonArray = new JArray();

            foreach (var kvp in value)
            {
                var itemJson = JToken.FromObject(kvp.Value, serializer);
                jsonArray.Add(itemJson);
            }

            jsonArray.WriteTo(writer);
        }
    }
}



