﻿using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Arugula;

namespace Arugula.Games
{
    public class Scoreboard : IEnumerable<Scoreboard.Entry>
    {
        static Dictionary<string, Scoreboard> scoreboards = new Dictionary<string, Scoreboard>();
        public static Scoreboard Get(string id) => scoreboards.ContainsKey(id) ? scoreboards[id] : null;
        public static IEnumerable<Scoreboard> All => scoreboards.Values.AsEnumerable();
        public static Scoreboard Register(Scoreboard sb)
        {
            scoreboards[sb.id] = sb;
            return sb;
        }

        [System.Serializable]
        public class Entry
        {
            public event System.Action<Entry> OnUpdated = delegate { };

            public string name;
            public int value;
            public int time;
            public string meta;
            public System.DateTime dateTime => (new System.DateTime(1970, 1, 1) + System.TimeSpan.FromSeconds(time)).ToLocalTime();

            public Entry(string name, int value, string meta)
            {
                this.name = name;
                this.value = value;
                this.meta = meta;
                this.time = (int)(System.DateTime.UtcNow - new System.DateTime(1970, 1, 1)).TotalSeconds;
            }

            public void Update(int value)
            {
                this.value = value;
                this.time = (int)(System.DateTime.UtcNow - new System.DateTime(1970, 1, 1)).TotalSeconds;
                OnUpdated(this);
            }
        }

        public event System.Action<Entry> OnEntryAdded = delegate { };
        public event System.Action OnCleared = delegate { };

        public string id;
        public string name;
        public string info = null;
        public bool desc = false;
        public float mult = 1;
        public int size = 10;
        [SerializeField]
        List<Entry> entries;

        public int Count => entries.Count;
        public Entry this[int index] => entries[index];
        public float GetDisplayValue(int index) => entries[index].value * mult;
        public void Add(string name, int value, string metaData = null)
        {
            Add(new Entry(name, value, metaData));
        }

        public void Add(Entry e)
        {
            entries.Add(e);
            Sort();
            if (entries.Count > size)
                entries.RemoveAt(Count);

            OnEntryAdded(e);
        }

        public Scoreboard(string id, string name, string info = null, bool desc = false, float multiplier = 1, int size = 10)
        {
            this.id = id;
            this.name = name;
            this.info = info;
            this.desc = desc;
            this.mult = multiplier;
            this.size = size;
            this.entries = new List<Entry>();

            if (PlayerPrefs.HasKey(id))
                JsonUtility.FromJsonOverwrite(PlayerPrefs.GetString(id), this);
        }

        public Scoreboard(string json)
        {
            JsonUtility.FromJsonOverwrite(json, this);
        }

        public void Sort()
        {
            if (Count <= 1)
                return;

            if (desc)
                entries.Sort((a, b) => b.value.CompareTo(a.value));
            else
                entries.Sort((a, b) => a.value.CompareTo(b.value));
        }

        public string GetJson(bool prettyPrint = true)
        {
            return JsonUtility.ToJson(this, prettyPrint);
        }

        public void Clear()
        {
            entries.Clear();
        }

        public void SaveToPrefs()
        {
            PlayerPrefs.SetString(id, GetJson(false));
        }

        public IEnumerator<Entry> GetEnumerator()
        {
            return entries.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return entries.GetEnumerator();
        }
    }
}
