using AyCode.Core.Extensions;
using AyCode.Core.Interfaces;
using AyCode.Core.Serializers;
using JsonIgnoreAttribute = Newtonsoft.Json.JsonIgnoreAttribute;
using STJIgnore = System.Text.Json.Serialization.JsonIgnoreAttribute;

namespace AyCode.Services.SignalRs;

/// <summary>
/// Message container for serialized parameter IDs.
/// Optimized for common primitive types to avoid full JSON overhead.
/// </summary>
[Obsolete("Use direct object[] binary serialization instead of IdMessage JSON wrapper.")]
public class IdMessage
{
    public List<string> Ids { get; private set; }

    public IdMessage()
    {
        Ids = [];
    }

    /// <summary>
    /// Creates IdMessage with multiple parameters serialized directly as JSON.
    /// </summary>
    public IdMessage(object[] ids)
    {
        Ids = new List<string>(ids.Length);
        for (var i = 0; i < ids.Length; i++)
        {
            Ids.Add(SignalRSerializationHelper.SerializePrimitiveToJson(ids[i]));
        }
    }

    /// <summary>
    /// Creates IdMessage with a single parameter serialized as JSON.
    /// </summary>
    public IdMessage(object id)
    {
        Ids = [SignalRSerializationHelper.SerializePrimitiveToJson(id)];
    }

    /// <summary>
    /// Creates IdMessage with multiple Guid parameters.
    /// </summary>
    public IdMessage(IEnumerable<Guid> ids)
    {
        var idsArray = ids as Guid[] ?? ids.ToArray();
        Ids = new List<string>(idsArray.Length);
        for (var i = 0; i < idsArray.Length; i++)
        {
            Ids.Add(SignalRSerializationHelper.SerializeGuidToJson(idsArray[i]));
        }
    }

    public override string ToString() => string.Join("; ", Ids);
}

/// <summary>
/// Message containing JSON-serialized post data.
/// </summary>
[Obsolete("Use direct object[] binary serialization instead of JSON-in-Binary wrapper.")]
public class SignalPostJsonMessage
{
    public string PostDataJson { get; set; } = "";

    public SignalPostJsonMessage() { }
    protected SignalPostJsonMessage(string postDataJson) => PostDataJson = postDataJson;
}

/// <summary>
/// Generic message containing JSON-serialized post data with typed access.
/// </summary>
[Obsolete("Use direct object[] binary serialization instead of JSON-in-Binary wrapper.")]
public class SignalPostJsonDataMessage<TPostDataType> : SignalPostJsonMessage, ISignalPostMessage<TPostDataType>
{
    [JsonIgnore]
    [STJIgnore]
    private TPostDataType? _postData;

    [JsonIgnore]
    [STJIgnore]
    public TPostDataType PostData
    {
        get => _postData ??= PostDataJson.JsonTo<TPostDataType>()!;
        private init
        {
            _postData = value;
            PostDataJson = _postData.ToJson();
        }
    }

    public SignalPostJsonDataMessage() : base() { }
    public SignalPostJsonDataMessage(TPostDataType postData) => PostData = postData;
    public SignalPostJsonDataMessage(string postDataJson) : base(postDataJson) { }
}

/// <summary>
/// Simple message containing post data.
/// </summary>
[Obsolete("Use direct object[] binary serialization instead of message wrappers.")]
public class SignalPostMessage<TPostData>(TPostData postData) : ISignalPostMessage<TPostData>
{
    public TPostData? PostData { get; set; } = postData;
}

[Obsolete("Use direct object[] binary serialization instead of message wrappers.")]
public interface ISignalPostMessage<TPostData> : ISignalRMessage
{
    TPostData? PostData { get; }
}

/// <summary>
/// Message for requesting by Guid ID.
/// </summary>
public class SignalRequestByIdMessage(Guid id) : ISignalRequestMessage<Guid>, IId<Guid>
{
    public Guid Id { get; set; } = id;
}

public interface ISignalRequestMessage<TRequestId> : ISignalRMessage
{
    TRequestId Id { get; set; }
}

public interface ISignalRMessage { }

public interface ISignalResponseMessage : ISignalRMessage
{
    int MessageTag { get; set; }
    SignalResponseStatus Status { get; set; }
}

public enum SignalResponseStatus : byte
{
    Error = 0,
    Success = 5
}

/// <summary>
/// Unified signal response message that supports both JSON and Binary serialization.
/// JSON mode uses GZip compression for reduced payload size.
/// Optimized: uses pooled buffers for decompression, zero-copy deserialization path.
/// </summary>
/// <summary>
/// Lightweight response container for client request-response pipeline and stream wire format.
/// Main send path does NOT use this — server sends (signalParams + object) directly.
/// Used by: (1) client OnReceiveMessage → stores in requestModel, (2) stream path (serialized as blob).
/// </summary>
public sealed class SignalResponseDataMessage : ISignalResponseMessage
{
    public int MessageTag { get; set; }
    public SignalResponseStatus Status { get; set; }
    public AcSerializerType DataSerializerType { get; set; }

    /// <summary>
    /// Raw response object — on client: protocol-deserialized typed object or byte[].
    /// On server (stream path only): raw object for blob serialization.
    /// </summary>
    [JsonIgnore] [STJIgnore]
    public object? RawResponseData { get; set; }

    public SignalResponseDataMessage() { }

    public SignalResponseDataMessage(int messageTag, SignalResponseStatus status)
    {
        MessageTag = messageTag;
        Status = status;
    }

    /// <summary>Stream path constructor: stores raw object for blob serialization.</summary>
    public SignalResponseDataMessage(int messageTag, SignalResponseStatus status, object? responseData, AcSerializerOptions serializerOptions)
        : this(messageTag, status)
    {
        DataSerializerType = serializerOptions.SerializerType;
        RawResponseData = responseData;
    }

    /// <summary>
    /// Extracts response data as T.
    /// Protocol eagerly deserializes via SignalDataType → RawResponseData is typed object → direct cast.
    /// Consumer's responsibility to handle byte[] if T is byte[].
    /// </summary>
    public T? GetResponseData<T>()
    {
        var data = RawResponseData;
        if (data is T typed) return typed;

        return data == null ? default : throw new InvalidCastException($"RawResponseData is NOT T! {typeof(T)} <> {data.GetType()}");
    }
}

public interface IAcSignalRHubClient : IAcSignalRHubBase
{
    Task SendMessageToServerAsync(int messageTag, object[]? parameters, int? requestId);
}