package net.ranides.assira.time2.json;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import net.ranides.assira.time2.DateTimeFormatters;
import net.ranides.assira.time2.DateTimeUtils;
import net.ranides.assira.time2.ZonedTime;

import java.io.IOException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

public class ZonedTimeSerializer extends StdSerializer<ZonedTime> implements ContextualSerializer {

    private final DateTimeFormatter formatter;
    private final boolean           useNumeric;

    protected ZonedTimeSerializer() {
        this(DateTimeFormatters.DATE.withZone(DateTimeUtils.ZONE_PL), false);
    }

    public ZonedTimeSerializer(DateTimeFormatter formatter, boolean useNumeric) {
        super(ZonedTime.class);
        this.formatter = formatter;
        this.useNumeric = useNumeric;
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializers,
        BeanProperty property) throws JsonMappingException {
        JsonFormat.Value format = findFormatOverrides(serializers, property, handledType());
        if (format == null) {
            return this;
        }
        if (format.getShape().isNumeric()) {
            return new ZonedTimeSerializer(formatter, true);
        }

        DateTimeFormatter formatter1 = format.hasPattern()
            ? DateTimeFormatter.ofPattern(format.getPattern())
            : DateTimeFormatters.DATE;

        DateTimeFormatter formatter2 = formatter1
            .withLocale(format.hasLocale() ? format.getLocale() : DateTimeFormatters.LOCALE_PL)
            .withZone(format.hasTimeZone() ? format.getTimeZone().toZoneId() : DateTimeUtils.ZONE_UTC);

        return new ZonedTimeSerializer(formatter2, false);
    }

    @Override
    public void serialize(ZonedTime value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        if (useNumeric) {
            long seconds = value.withZoneUtc().toNanoOfDay() / ChronoUnit.SECONDS.getDuration().toNanos();
            gen.writeNumber(seconds);
        } else {
            gen.writeString(DateTimeFormatters.format(formatter, value.withDate(ZonedDateTime.now())));
        }
    }

}
