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

namespace FSO.Common.Rendering.Emoji
{
    public class EmojiDictionary
    {
        public Dictionary<string, string> NameToEmojis = new Dictionary<string, string>();
        public Dictionary<string, List<string>> KeywordToCandidates = new Dictionary<string, List<string>>();
        public Dictionary<string, List<string>> CandidatesToKeywords = new Dictionary<string, List<string>>();

        public EmojiDictionary()
        {
            JObject emojis;
            using (var emojiDict = new StreamReader(
                new FileStream(Path.Combine(FSOEnvironment.ContentDir, "UI/emojis.json"), FileMode.Open, FileAccess.Read, FileShare.Read)))
            {
                emojis = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(emojiDict.ReadToEnd());
            }

            foreach (var token in emojis)
            {
                var charValue = token.Value.Value<string>("char");
                var twemojiID = ToCodePoint(charValue);
                NameToEmojis[token.Key] = twemojiID;
                var keys = token.Value.Value<JArray>("keywords");
                foreach (var key in keys)
                    AddKeyword(key.Value<string>(), token.Key);
            }

            using (var emojiDict = new StreamReader(
                new FileStream(Path.Combine(FSOEnvironment.ContentDir, "UI/customemojis.json"), FileMode.Open, FileAccess.Read, FileShare.Read)))
            {
                emojis = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(emojiDict.ReadToEnd());
            }

            foreach (var token in emojis)
            {
                NameToEmojis[token.Key] = "!" + token.Value.Value<string>("url");
                var keys = token.Value.Value<JArray>("keywords");
                foreach (var key in keys)
                    AddKeyword(key.Value<string>(), token.Key);
            }
        }

        public void AddKeyword(string keyword, string candidate)
        {
            List<string> cand;
            if (!KeywordToCandidates.TryGetValue(keyword, out cand))
            {
                cand = new List<string>();
                KeywordToCandidates[keyword] = cand;
            }
            cand.Add(candidate);

            if (!CandidatesToKeywords.TryGetValue(candidate, out cand))
            {
                cand = new List<string>();
                CandidatesToKeywords[candidate] = cand;
            }
            cand.Add(keyword);
        }

        public string ToCodePoint(string str)
        {
            var cs = str.ToCharArray();
            var i = 0;
            var c = 0;
            var p = 0;
            var r = new List<string>();
            var zeroWidth = str.Any(x => x == '\x200D');
            while (i < cs.Length)
            {
                c = cs[i++];
                if (c == 0xfe0f && !zeroWidth) continue; //"as image", just ignore this
                if (p > 0)
                {
                    r.Add((0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)).ToString("x"));
                    p = 0;
                }
                else if (0xD800 <= c && c <= 0xDBFF)
                {
                    p = c;
                }
                else
                {
                    r.Add(c.ToString("x"));
                }
            }
            return string.Join("-", r);
        }
    }
}