using System.Diagnostics;
using InnovEnergy.Lib.Protocols.DBus.Protocol.DataTypes;
using InnovEnergy.Lib.Protocols.DBus.Protocol.DataTypes.Convert;
using InnovEnergy.Lib.Protocols.DBus.Protocol.Header;

namespace InnovEnergy.Lib.Protocols.DBus.Protocol;

using HeaderType      = ValueTuple<Byte, Byte, Byte, Byte, UInt32, UInt32, IReadOnlyList<(Byte, Variant)>>;

public static class Replies
{
    
    // https://www.freedesktop.org/software/systemd/man/sd-bus-errors.html
    
    public static Message CreateErrorReply(this Message msg, String error)
    {
        Debug.Assert(msg.Type == MessageType.MethodCall);
        
        var signature = error.GetSignature().AsRootSignature();

        var fields = new[]
        {
            ((Byte) FieldCode.Destination, msg.Sender!.Variant()),
            ((Byte) FieldCode.ErrorName  , "DBus.Error".Variant()),
            ((Byte) FieldCode.Signature  , signature.Variant()),
            ((Byte) FieldCode.ReplySerial, msg.Serial.Variant()),
        };

        ValueTuple<Byte, Byte, Byte, Byte, UInt32, UInt32, IReadOnlyList<(Byte, Variant)>> header =
        (
            (Byte) Env.Endianness,
            (Byte) MessageType.Error,
            (Byte) HeaderFlags.NoReplyExpected,
            Message.ProtocolVersion, 
            (UInt32) signature.MeasureSize(error),
            SerialSource.Next(),
            fields
        );

        return new Message(header, error);
    }

    public static Message CreateMethodReturn(this Message msg, Object payload)
    {
        var signature = payload.GetSignature().AsRootSignature();

        var fields = new[]
        {
            ((Byte) FieldCode.Destination, msg.Sender!.Variant()),
            ((Byte) FieldCode.Signature  , signature.Variant()),
            ((Byte) FieldCode.ReplySerial, msg.Serial.Variant()),
        };

        HeaderType header =
        (
            (Byte)Env.Endianness,
            (Byte)MessageType.MethodReturn,
            (Byte)HeaderFlags.NoReplyExpected,
            Message.ProtocolVersion,
            (UInt32)signature.MeasureSize(payload),
            SerialSource.Next(),
            fields
        );

        return new Message(header, payload);
    }
    
}