package ru.yandex.qe.dispenser.api.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.Set;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.kotlin.KotlinModule;
import org.jetbrains.annotations.NotNull;

public enum SerializationUtils {
    ;

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper().registerModules(new Jdk8Module(),
            new JavaTimeModule(), new KotlinModule.Builder().build());
    private static final ObjectMapper OBJECT_MAPPER_NUMBERS_AS_STRINGS = new ObjectMapper()
            .registerModules(new Jdk8Module(), new JavaTimeModule(), new KotlinModule.Builder().build())
            .configure(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, true);


    @NotNull
    public static Set<String> toStringSet(@NotNull final Object node) {
        return OBJECT_MAPPER.convertValue(node, new TypeReference<Set<String>>() {
        });
    }

    @NotNull
    public static String[] toStrings(@NotNull final Object node) {
        return OBJECT_MAPPER.convertValue(node, String[].class);
    }

    @NotNull
    public static <T> T readValue(@NotNull final String content, @NotNull final Class<T> valueType) throws IOException {
        return OBJECT_MAPPER.readValue(content, valueType);
    }

    @NotNull
    public static <T> T readValue(@NotNull final String content, @NotNull final TypeReference<T> valueTypeRef) throws IOException {
        return OBJECT_MAPPER.readValue(content, valueTypeRef);
    }

    @NotNull
    public static <T> T readValue(@NotNull final InputStream src, @NotNull final Class<T> valueType) throws IOException {
        return OBJECT_MAPPER.readValue(src, valueType);
    }

    @NotNull
    public static <T> T readValue(@NotNull final InputStream src, @NotNull final TypeReference<T> valueTypeRef) throws IOException {
        return OBJECT_MAPPER.readValue(src, valueTypeRef);
    }

    @NotNull
    public static <V> V convertValue(@NotNull final Object fromValue, @NotNull final Class<V> toValueType) {
        return OBJECT_MAPPER.convertValue(fromValue, toValueType);
    }

    @NotNull
    public static <V> V convertValue(@NotNull final Object fromValue, @NotNull final TypeReference<V> toValueTypeRef) {
        return OBJECT_MAPPER.convertValue(fromValue, toValueTypeRef);
    }

    @NotNull
    public static String writeValueAsString(@NotNull final Object value) {
        try {
            return OBJECT_MAPPER.writeValueAsString(value);
        } catch (JsonProcessingException e) {
            throw new UncheckedIOException(e);
        }
    }

    public static <T> T readValueNumbersAsStrings(String content, TypeReference<T> valueTypeRef) {
        try {
            return OBJECT_MAPPER_NUMBERS_AS_STRINGS.readValue(content, valueTypeRef);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    public static <T> T readValueNumbersAsStrings(String content, Class<T> valueType) {
        try {
            return OBJECT_MAPPER_NUMBERS_AS_STRINGS.readValue(content, valueType);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    public static String writeValueAsStringNumbersAsStrings(Object value) {
        try {
            return OBJECT_MAPPER_NUMBERS_AS_STRINGS.writeValueAsString(value);
        } catch (JsonProcessingException e) {
            throw new UncheckedIOException(e);
        }
    }

}
