package de.accso.flexinale.common.infrastructure.eventbus;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import de.accso.flexinale.common.api.event.Event;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public final class EventSerializationHelper {
    private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME;

    private static final ObjectMapper jsonMapper;

    static {
        jsonMapper = new ObjectMapper();
        jsonMapper.findAndRegisterModules();
        jsonMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);

        // register module for date/time (de)serialization, in ISO format ISO8601, e.g. 2022-05-06T11:12:13Z
        SimpleModule localDateTimeModule = new SimpleModule();
        localDateTimeModule.addSerializer(LocalDateTime.class, new JsonSerializer<>() {
            @Override
            public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                gen.writeString(value.format(dateTimeFormatter));
            }
        });
        localDateTimeModule.addDeserializer(LocalDateTime.class, new JsonDeserializer<>() {
            @Override
            public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
                return LocalDateTime.parse(p.getValueAsString(), dateTimeFormatter);
            }
        });
        jsonMapper.registerModule(localDateTimeModule);
    }

    public static String serializeEvent2JsonString(final Event event) throws JsonProcessingException {
        return jsonMapper.writeValueAsString(event);
    }

    public static <E extends Event> E deserializeJsonString2Event(
            final String jsonString, final Class<E> eventType) throws JsonProcessingException {
        return jsonMapper.readValue(jsonString, eventType);
    }
}
