using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TMPro;
using UnityEngine;

namespace eagle {
    public static class GeneratedTextGlyphValidator {
#if UNITY_EDITOR || DEVELOPMENT_BUILD
        private static readonly HashSet<string> ReportedMissingGlyphs = new();
#endif

        public static void
        LogMissingGlyphs(TMP_Text textComponent, string renderedText, string context) {
#if UNITY_EDITOR || DEVELOPMENT_BUILD
            if (String.IsNullOrEmpty(renderedText)) { return; }

            var fontAsset = textComponent.font ?? TMP_Settings.defaultFontAsset;
            if (fontAsset == null) { return; }

            var visibleCharacters = VisibleCharacters(renderedText);
            if (visibleCharacters.Length == 0) { return; }

            if (fontAsset.HasCharacters(
                        visibleCharacters,
                        out uint[] missingUnicodes,
                        true,
                        false)) {
                return;
            }

            var newlyReported = missingUnicodes
                                        .Where(unicode => ReportedMissingGlyphs.Add(
                                                       ReportKey(fontAsset, unicode)))
                                        .Select(DescribeUnicode)
                                        .ToList();
            if (newlyReported.Count == 0) { return; }

            Debug.LogWarning(
                    $"Generated text contains glyphs missing from TMP font asset '{fontAsset.name}' and its fallbacks: " +
                            $"{String.Join(", ", newlyReported)}. Context: {context}. " +
                            "Bake these glyphs into the static TMP fallback font before shipping text that can contain them.",
                    textComponent);
#endif
        }

#if UNITY_EDITOR || DEVELOPMENT_BUILD
        private static string VisibleCharacters(string text) {
            var builder = new StringBuilder(text.Length);
            foreach (var character in text.Where(character => !Char.IsControl(character))) {
                builder.Append(character);
            }

            return builder.ToString();
        }

        private static string ReportKey(TMP_FontAsset fontAsset, uint unicode) {
            return $"{fontAsset.GetEntityId()}:{unicode:X}";
        }

        private static string DescribeUnicode(uint unicode) {
            return $"U+{unicode:X4} '{Char.ConvertFromUtf32((int)unicode)}'";
        }
#endif
    }
}
