using System;
using System.CodeDom.Compiler;
using System.Globalization;
using System.IO;

namespace Spectre.Console.SourceGenerator.Emojis;

/// <summary>
/// Emits C# source code for emojis.
/// </summary>
internal static class EmojiEmitter
{
    /// <summary>
    /// Legacy emoji aliases for backwards compatibility.
    /// These emojis were renamed in newer Unicode versions but we maintain the old names.
    /// Format: (OldName, OldIdentifier, NewName, Description)
    /// </summary>
    private static readonly (string OldName, string OldIdentifier, string NewName, string Description)[] LegacyAliases =
    [
        // "hugging face" was renamed to "smiling face with open hands"
        ("HuggingFace", "hugging_face", "SmilingFaceWithOpenHands", "Hugging face"),
        // "knocked out face" was renamed to "face with crossed-out eyes"
        ("KnockedOutFace", "knocked_out_face", "FaceWithCrossedOutEyes", "Knocked-out face"),
        // "pouting face" was renamed to "enraged face"
        ("PoutingFace", "pouting_face", "EnragedFace", "Pouting face")
    ];

    /// <summary>
    /// Converts a Unicode escape sequence like "\U0001F9EE" to the actual character.
    /// </summary>
    private static string CodeToEmoji(string code)
    {
        // Code is in format "\U00000000" - extract the hex part
        if (code.StartsWith("\\U", StringComparison.Ordinal) && code.Length == 10)
        {
            var hex = code.Substring(2);
            if (int.TryParse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var codePoint))
            {
                return char.ConvertFromUtf32(codePoint);
            }
        }

        return string.Empty;
    }

    private const string AutoGeneratedHeader = """
        //------------------------------------------------------------------------------
        // <auto-generated>
        //     This code was generated by a tool.
        //
        //     Changes to this file may cause incorrect behavior and will be lost if
        //     the code is regenerated.
        // </auto-generated>
        //------------------------------------------------------------------------------

        """;

    /// <summary>
    /// Emits the Emoji.Generated.g.cs file content.
    /// </summary>
    public static string Emit(EquatableArray<EmojiModel> emojis)
    {
        using var stringWriter = new StringWriter();
        using var writer = new IndentedTextWriter(stringWriter, "    ");

        writer.WriteLine(AutoGeneratedHeader);
        writer.WriteLine("using System;");
        writer.WriteLine("using System.Collections.Generic;");
        writer.WriteLine();
        writer.WriteLine("namespace Spectre.Console");
        writer.WriteLine("{");
        writer.Indent++;

        writer.WriteLine("/// <summary>");
        writer.WriteLine("/// Utility for working with emojis.");
        writer.WriteLine("/// </summary>");
        writer.WriteLine("public static partial class Emoji");
        writer.WriteLine("{");
        writer.Indent++;

        // Emit _emojis dictionary
        writer.WriteLine("private static readonly Dictionary<string, string> _emojis");
        writer.Indent++;
        writer.WriteLine("= new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)");
        writer.Indent--;
        writer.WriteLine("{");
        writer.Indent++;

        foreach (var emoji in emojis)
        {
            writer.WriteLine($"{{ \"{emoji.Identifier}\", Emoji.Known.{emoji.Name} }},");
        }

        // Emit legacy aliases for backwards compatibility
        foreach (var (oldName, oldIdentifier, newName, _) in LegacyAliases)
        {
            writer.WriteLine($"{{ \"{oldIdentifier}\", Emoji.Known.{newName} }},");
        }

        writer.Indent--;
        writer.WriteLine("};");
        writer.WriteLine();

        // Emit Known class
        writer.WriteLine("/// <summary>");
        writer.WriteLine("/// Contains well-known emojis.");
        writer.WriteLine("/// </summary>");
        writer.WriteLine("public static class Known");
        writer.WriteLine("{");
        writer.Indent++;

        foreach (var emoji in emojis)
        {
            var emojiChar = CodeToEmoji(emoji.Code);
            writer.WriteLine("/// <summary>");
            writer.WriteLine($"/// Gets the \"{emoji.Description}\" emoji. {emojiChar}");
            writer.WriteLine("/// </summary>");
            writer.WriteLine($"/// <remarks>");
            writer.WriteLine($"/// Lookup: <c>{emoji.Identifier}</c>");
            writer.WriteLine($"/// </remarks>");
            writer.WriteLine($"public const string {emoji.Name} = \"{emoji.Code}\";");
            writer.WriteLine();
        }

        // Emit legacy aliases for backwards compatibility
        foreach (var (oldName, oldIdentifier, newName, description) in LegacyAliases)
        {
            writer.WriteLine("/// <summary>");
            writer.WriteLine($"/// Gets the \"{description}\" emoji.");
            writer.WriteLine("/// </summary>");
            writer.WriteLine($"/// <remarks>");
            writer.WriteLine($"/// Lookup: <c>{oldIdentifier}</c><br/>");
            writer.WriteLine($"/// This is a legacy alias for <see cref=\"{newName}\"/>.");
            writer.WriteLine($"/// </remarks>");
            writer.WriteLine($"public const string {oldName} = {newName};");
            writer.WriteLine();
        }

        writer.Indent--;
        writer.WriteLine("}");

        writer.Indent--;
        writer.WriteLine("}");
        writer.Indent--;
        writer.WriteLine("}");

        return stringWriter.ToString();
    }
}
