using Dalamud.Game.Text.SeStringHandling;
using HellionChat.Code;
using MessagePack;

namespace HellionChat;

[Union(0, typeof(TextChunk))]
[Union(1, typeof(IconChunk))]
[MessagePackObject]
public abstract class Chunk
{
    [IgnoreMember]
    internal Message? Message { get; set; }

    [Key(0)]
    public ChunkSource Source { get; set; }

    [Key(1)]
    [MessagePackFormatter(typeof(PayloadMessagePackFormatter))]
    public Payload? Link { get; set; }

    protected Chunk(ChunkSource source, Payload? link)
    {
        Source = source;
        Link = link;
    }

    internal SeString? GetSeString() =>
        Source switch
        {
            ChunkSource.None => null,
            ChunkSource.Sender => Message?.SenderSource,
            ChunkSource.Content => Message?.ContentSource,
            _ => null,
        };

    // Returns basic text for hashing (content for TextChunk, icon name for IconChunk)
    internal string StringValue()
    {
        return this switch
        {
            TextChunk text => text.Content,
            IconChunk icon => icon.Icon.ToString(),
            _ => "",
        };
    }
}

public enum ChunkSource
{
    None,
    Sender,
    Content,
}

[MessagePackObject(AllowPrivate = true)]
public class TextChunk : Chunk
{
    [Key(2)]
    public ChatType? FallbackColour;

    [Key(3)]
    public uint? Foreground;

    [Key(4)]
    public uint? Glow;

    [Key(5)]
    public bool Italic;

    [Key(6)]
    public string Content;

    private TextChunk(Chunk chunk, string content)
        : base(chunk.Source, chunk.Link)
    {
        Content = content;
    }

    internal TextChunk(ChunkSource source, Payload? link, string content)
        : base(source, link)
    {
        // This has been null in the past, and it broke rendering code.
        // ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract
        Content = content ?? "";
    }

    // ReSharper disable once UnusedMember.Global // Used by MessagePack
    public TextChunk(
        ChunkSource source,
        Payload? link,
        ChatType? fallbackColour,
        uint? foreground,
        uint? glow,
        bool italic,
        string content
    )
        : base(source, link)
    {
        FallbackColour = fallbackColour;
        Foreground = foreground;
        Glow = glow;
        Italic = italic;
        // See above.
        // ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract
        Content = content ?? "";
    }

    public TextChunk NewWithStyle(ChunkSource source, Payload? link, string content)
    {
        return new TextChunk(source, link, content)
        {
            FallbackColour = FallbackColour,
            Foreground = Foreground,
            Glow = Glow,
            Italic = Italic,
        };
    }

    public TextChunk NewWithStyle(Chunk chunk, string content)
    {
        return new TextChunk(chunk, content)
        {
            FallbackColour = FallbackColour,
            Foreground = Foreground,
            Glow = Glow,
            Italic = Italic,
        };
    }
}

[MessagePackObject(AllowPrivate = true)]
public class IconChunk : Chunk
{
    [Key(2)]
    public BitmapFontIcon Icon { get; set; }

    public IconChunk(ChunkSource source, Payload? link, BitmapFontIcon icon)
        : base(source, link)
    {
        Icon = icon;
    }
}
