#nullable enable
using System;
using IGP.Multiplayer.Models;

namespace IGP.Multiplayer
{
    public enum IGPRealtimeTransport
    {
        Kcp = 0,
        Udp = 1,
        Tcp = 2,
    }

    [Serializable]
    public sealed class IGPMultiplayerConnectionChangedEvent
    {
        public IGPRealtimeConnectionState PreviousState { get; }
        public IGPRealtimeConnectionState State { get; }
        public bool IsReady { get; }
        public string Reason { get; }

        public IGPMultiplayerConnectionChangedEvent(
            IGPRealtimeConnectionState previousState,
            IGPRealtimeConnectionState state,
            bool isReady,
            string reason)
        {
            PreviousState = previousState;
            State = state;
            IsReady = isReady;
            Reason = reason ?? string.Empty;
        }
    }

    public enum IGPRoomChangeKind
    {
        Joined = 0,
        Updated = 1,
        Left = 2,
    }

    [Flags]
    public enum IGPRoomChangeFlags
    {
        None = 0,
        Players = 1 << 0,
        Host = 1 << 1,
        Status = 1 << 2,
        Map = 1 << 3,
        SceneGate = 1 << 4,
        Teams = 1 << 5,
        Metadata = 1 << 6,
    }

    [Serializable]
    public sealed class IGPRoomChangedEvent
    {
        public IGPRoomChangeKind Kind { get; }
        public Room? PreviousRoom { get; }
        public Room? Room { get; }
        public Player? CurrentPlayer { get; }
        public IGPRoomChangeFlags Changes { get; }
        public string Reason { get; }

        public IGPRoomChangedEvent(
            IGPRoomChangeKind kind,
            Room? previousRoom,
            Room? room,
            Player? currentPlayer,
            IGPRoomChangeFlags changes,
            string reason)
        {
            Kind = kind;
            PreviousRoom = previousRoom;
            Room = room;
            CurrentPlayer = currentPlayer;
            Changes = changes;
            Reason = reason ?? string.Empty;
        }
    }

    [Serializable]
    public sealed class IGPMessageReceivedEvent
    {
        public string MessageType { get; }
        public string RoomId { get; }
        public string SenderPlayerId { get; }
        public string TargetPlayerId { get; }
        public object? Content { get; }
        public string Timestamp { get; }

        public IGPMessageReceivedEvent(
            string messageType,
            string roomId,
            string senderPlayerId,
            string targetPlayerId,
            object? content,
            string timestamp)
        {
            MessageType = messageType ?? string.Empty;
            RoomId = roomId ?? string.Empty;
            SenderPlayerId = senderPlayerId ?? string.Empty;
            TargetPlayerId = targetPlayerId ?? string.Empty;
            Content = content;
            Timestamp = timestamp ?? string.Empty;
        }
    }

    [Serializable]
    public sealed class IGPMultiplayerErrorEvent
    {
        public string Code { get; }
        public string Message { get; }
        public string Source { get; }
        public IGPRealtimeTransport? Transport { get; }
        public bool IsTerminal { get; }
        public object? Details { get; }

        public IGPMultiplayerErrorEvent(
            string code,
            string message,
            string source,
            IGPRealtimeTransport? transport,
            bool isTerminal,
            object? details = null)
        {
            Code = code ?? string.Empty;
            Message = message ?? string.Empty;
            Source = source ?? string.Empty;
            Transport = transport;
            IsTerminal = isTerminal;
            Details = details;
        }
    }

    internal sealed class IGPTransportMessageReceived
    {
        public IGPRealtimeTransport Transport { get; }
        public Message Message { get; }

        public IGPTransportMessageReceived(IGPRealtimeTransport transport, Message message)
        {
            Transport = transport;
            Message = message;
        }
    }

    internal sealed class IGPTransportConnectionChanged
    {
        public IGPRealtimeTransport Transport { get; }
        public bool IsConnected { get; }
        public string Reason { get; }

        public IGPTransportConnectionChanged(
            IGPRealtimeTransport transport,
            bool isConnected,
            string reason)
        {
            Transport = transport;
            IsConnected = isConnected;
            Reason = reason ?? string.Empty;
        }
    }

    internal sealed class IGPTransportFault
    {
        public IGPRealtimeTransport Transport { get; }
        public string Code { get; }
        public string Message { get; }
        public bool IsTerminal { get; }
        public object? Details { get; }

        public IGPTransportFault(
            IGPRealtimeTransport transport,
            string code,
            string message,
            bool isTerminal,
            object? details = null)
        {
            Transport = transport;
            Code = code ?? string.Empty;
            Message = message ?? string.Empty;
            IsTerminal = isTerminal;
            Details = details;
        }
    }
}
