/*
 * Copyright (c) 2016-2021 Flux Capacitor.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.fluxcapacitor.javaclient.common;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.fluxcapacitor.common.api.Metadata;
import io.fluxcapacitor.common.api.SerializedMessage;
import io.fluxcapacitor.javaclient.common.serialization.Serializer;
import lombok.AllArgsConstructor;
import lombok.Value;
import lombok.With;
import lombok.experimental.NonFinal;

import java.time.Instant;
import java.util.Map;

import static io.fluxcapacitor.javaclient.FluxCapacitor.currentClock;
import static io.fluxcapacitor.javaclient.FluxCapacitor.currentIdentityProvider;

@Value
@AllArgsConstructor
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@NonFinal
public class Message {

    public static Message asMessage(Object object) {
        return object instanceof Message ? (Message) object : new Message(object);
    }

    @With
    @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
    Object payload;
    @With
    Metadata metadata;
    String messageId;
    Instant timestamp;

    public Message(Object payload) {
        this(payload, Metadata.empty(), currentIdentityProvider().nextTechnicalId(), currentClock().instant());
    }

    public Message(Object payload, Metadata metadata) {
        this(payload, metadata, currentIdentityProvider().nextTechnicalId(), currentClock().instant());
    }

    @SuppressWarnings("unchecked")
    public <R> R getPayload() {
        return (R) payload;
    }

    public Class<?> getPayloadClass() {
        return payload == null ? Void.class : payload.getClass();
    }

    public Message toMessage() {
        return this;
    }

    public Message addMetadata(Metadata metadata) {
        return withMetadata(getMetadata().with(metadata));
    }

    public Message addMetadata(String key, Object value) {
        return withMetadata(getMetadata().with(key, value));
    }

    public Message addMetadata(Object... keyValues) {
        return withMetadata(getMetadata().with(keyValues));
    }

    public Message addMetadata(Map<String, ?> values) {
        return withMetadata(getMetadata().with(values));
    }

    public SerializedMessage serialize(Serializer serializer) {
        return new SerializedMessage(serializer.serialize(getPayload()), getMetadata(), getMessageId(),
                                     getTimestamp().toEpochMilli());
    }
}

@@ -866,42 +866,8 @@
 er;%0A
-import lombok.AllArgsConstructor;%0A
 impo
@@ -941,16 +941,57 @@
 Final;%0A%0A
+import java.beans.ConstructorProperties;%0A
 import j
@@ -1029,16 +1029,43 @@
 til.Map;
+%0Aimport java.util.Optional;
 %0A%0Aimport
@@ -1221,28 +1221,8 @@
 lue%0A
-@AllArgsConstructor%0A
 @Jso
@@ -1672,221 +1672,600 @@
 ty()
-, currentIdentityProvider().nextTechnicalId(), currentClock().instant());%0A    %7D%0A%0A    public Message(Object payload, Metadata metadata) %7B%0A        this(payload, metadata, currentIdentityProvider().nextTechnicalId(),
+);%0A    %7D%0A%0A    public Message(Object payload, Metadata metadata) %7B%0A        this(payload, metadata, null, null);%0A    %7D%0A%0A    @ConstructorProperties(%7B%22payload%22, %22metadata%22, %22messageId%22, %22timestamp%22%7D)%0A    public Message(Object payload, Metadata metadata, String messageId, Instant timestamp) %7B%0A        this.payload = payload;%0A        this.metadata = Optional.ofNullable(metadata).orElseGet(Metadata::empty);%0A        this.messageId = Optional.ofNullable(messageId).orElseGet(() -%3E currentIdentityProvider().nextTechnicalId());%0A        this.timestamp = Optional.ofNullable(timestamp).orElseGet(() -%3E
  cur

Support deserializing a Message from json missing message id and timestamp