using Barotrauma.Items.Components;
using Microsoft.Xna.Framework;
using System;

namespace Barotrauma.Networking
{
    partial class ChatMessage
    {
        public virtual void ClientWrite(in SegmentTableWriter<ClientNetSegment> segmentTableWriter, IWriteMessage msg)
        {
            segmentTableWriter.StartNewSegment(ClientNetSegment.ChatMessage);
            msg.WriteUInt16(NetStateID);
            msg.WriteRangedInteger((int)Type, 0, Enum.GetValues(typeof(ChatMessageType)).Length - 1);
            msg.WriteRangedInteger((int)ChatMode, 0, Enum.GetValues(typeof(ChatMode)).Length - 1);
            msg.WriteString(Text);
        }

        public static void ClientRead(IReadMessage msg)
        {
            UInt16 id = msg.ReadUInt16();
            ChatMessageType type = (ChatMessageType)msg.ReadRangedInteger(0, Enum.GetValues(typeof(ChatMessageType)).Length - 1);
            PlayerConnectionChangeType changeType = PlayerConnectionChangeType.None;
            string txt = "";
            string styleSetting = string.Empty;

            if (type != ChatMessageType.Order)
            {
                changeType = (PlayerConnectionChangeType)msg.ReadByte();
            }
            txt = msg.ReadString();

            string senderName = msg.ReadString();
            Entity sender = null;
            Character senderCharacter = null;
            Client senderClient = null;
            bool hasSenderClient = msg.ReadBoolean();
            if (hasSenderClient)
            {
                string userId = msg.ReadString();
                senderClient = GameMain.Client.ConnectedClients.Find(c
                    => c.SessionOrAccountIdMatches(userId));
                if (senderClient != null) { senderName = senderClient.Name; }
            }
            bool hasSender = msg.ReadBoolean();
            if (hasSender)
            {
                sender = Entity.FindEntityByID(msg.ReadUInt16());
                senderCharacter = sender as Character;
                if (sender is Character or Item)
                {
                    senderName = OrderChatMessage.NameFromEntityOrNull(sender);
                }
            }

            Color? textColor = null;
            if (msg.ReadBoolean())
            {
                textColor = msg.ReadColorR8G8B8A8();
            }

            msg.ReadPadBits();

            switch (type)
            {
                case ChatMessageType.Default:
                    break;
                case ChatMessageType.Order:
                    var orderMessageInfo = OrderChatMessage.ReadOrder(msg);
                    if (orderMessageInfo.OrderIdentifier == Identifier.Empty)
                    {
                        DebugConsole.ThrowError("Invalid order message - order index out of bounds.");
                        if (NetIdUtils.IdMoreRecent(id, LastID)) { LastID = id; }
                        return;
                    }
                    var orderPrefab = orderMessageInfo.OrderPrefab ?? OrderPrefab.Prefabs[orderMessageInfo.OrderIdentifier];
                    Identifier orderOption = orderMessageInfo.OrderOption;
                    orderOption = orderOption.IfEmpty(
                        orderMessageInfo.OrderOptionIndex.HasValue && orderMessageInfo.OrderOptionIndex >= 0 && orderMessageInfo.OrderOptionIndex < orderPrefab.Options.Length
                            ? orderPrefab.Options[orderMessageInfo.OrderOptionIndex.Value]
                            : Identifier.Empty);
                    string targetRoom;

                    if (orderMessageInfo.TargetEntity is Hull targetHull)
                    {
                        targetRoom = targetHull.DisplayName.Value;
                    }
                    else
                    {
                        targetRoom = senderCharacter?.CurrentHull?.DisplayName?.Value;
                    }

                    if (GameMain.Client.GameStarted && Screen.Selected == GameMain.GameScreen)
                    {
                        Order order = null;
                        switch (orderMessageInfo.TargetType)
                        {
                            case Order.OrderTargetType.Entity:
                                order = new Order(orderPrefab, orderOption, orderMessageInfo.TargetEntity, orderPrefab.GetTargetItemComponent(orderMessageInfo.TargetEntity as Item), orderGiver: senderCharacter);
                                break;
                            case Order.OrderTargetType.Position:
                                order = new Order(orderPrefab, orderOption, orderMessageInfo.TargetPosition, orderGiver: senderCharacter);
                                break;
                            case Order.OrderTargetType.WallSection:
                                order = new Order(orderPrefab, orderOption, orderMessageInfo.TargetEntity as Structure, orderMessageInfo.WallSectionIndex, orderGiver: senderCharacter);
                                break;
                        }

                        if (order != null)
                        {
                            order = order.WithManualPriority(orderMessageInfo.Priority);
                            if (order.TargetAllCharacters)
                            {
                                var fadeOutTime = !orderPrefab.IsIgnoreOrder ? (float?)orderPrefab.FadeOutTime : null;
                                GameMain.GameSession?.CrewManager?.AddOrder(order, fadeOutTime);
                            }
                            else
                            {
                                orderMessageInfo.TargetCharacter?.SetOrder(order, orderMessageInfo.IsNewOrder);
                            }
                        }
                    }

                    if (NetIdUtils.IdMoreRecent(id, LastID))
                    {
                        Order order = null;
                        if (orderMessageInfo.TargetPosition != null)
                        {
                            order = new Order(orderPrefab, orderOption, orderMessageInfo.TargetPosition, orderGiver: senderCharacter)
                                .WithManualPriority(orderMessageInfo.Priority);
                        }
                        else if (orderMessageInfo.WallSectionIndex != null)
                        {
                            order = new Order(orderPrefab, orderOption, orderMessageInfo.TargetEntity as Structure, orderMessageInfo.WallSectionIndex, orderGiver: senderCharacter)
                                .WithManualPriority(orderMessageInfo.Priority);
                        }
                        else
                        {
                            order = new Order(orderPrefab, orderOption, orderMessageInfo.TargetEntity, orderPrefab.GetTargetItemComponent(orderMessageInfo.TargetEntity as Item), orderGiver: senderCharacter)
                                .WithManualPriority(orderMessageInfo.Priority);
                        }
                        GameMain.Client.AddChatMessage(
                            new OrderChatMessage(order, txt, orderMessageInfo.TargetCharacter, senderCharacter));
                        LastID = id;
                    }
                    return;
                case ChatMessageType.ServerMessageBox:
                    txt = TextManager.GetServerMessage(txt).Value;
                    break;
                case ChatMessageType.ServerMessageBoxInGame:
                    styleSetting = msg.ReadString();
                    txt = TextManager.GetServerMessage(txt).Value;
                    break;
                case ChatMessageType.BlockedBySpamFilter:
                    GameMain.Client.BlockedBySpamFilterTimer = BlockedBySpamFilterTime;
                    break;
            }

            if (NetIdUtils.IdMoreRecent(id, LastID))
            {
                switch (type)
                {
                    case ChatMessageType.MessageBox:
                    case ChatMessageType.ServerMessageBox:
                        //only show the message box if the text differs from the text in the currently visible box
                        if ((GUIMessageBox.VisibleBox as GUIMessageBox)?.Text?.Text != txt)
                        {
                            GUIMessageBox messageBox = new GUIMessageBox("", txt);
                            if (textColor != null) { messageBox.Text.TextColor = textColor.Value; }
                        }
                        break;
                    case ChatMessageType.ServerMessageBoxInGame:
                        {
                            GUIMessageBox messageBox = new GUIMessageBox("", txt, Array.Empty<LocalizedString>(), type: GUIMessageBox.Type.InGame, iconStyle: styleSetting);
                            if (textColor != null) { messageBox.Text.TextColor = textColor.Value; }
                        }
                        break;
                    case ChatMessageType.Console:
                        DebugConsole.NewMessage(txt, textColor == null ? MessageColor[(int)ChatMessageType.Console] : textColor.Value);
                        break;
                    case ChatMessageType.ServerLog:
                        if (!Enum.TryParse(senderName, out ServerLog.MessageType messageType))
                        {
                            return;
                        }
                        GameMain.Client.ServerSettings.ServerLog?.WriteLine(txt, messageType);
                        break;
                    default:
                        GameMain.Client.AddChatMessage(txt, type, senderName, senderClient, sender, changeType, textColor: textColor);
                        if (type == ChatMessageType.Radio && CanUseRadio(senderCharacter, out WifiComponent radio))
                        {
                            Signal s = new Signal(txt, sender: senderCharacter, source: radio.Item);
                            radio.TransmitSignal(s, sentFromChat: true);
                        }
                        break;
                }
                LastID = id;
            }
        }
    }
}
