package net.ranides.assira.time2.json;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonTokenId;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import net.ranides.assira.time2.DateTimeFormatters;
import net.ranides.assira.time2.DateTimeParsers;
import net.ranides.assira.time2.DateTimeUtils;
import net.ranides.assira.time2.ZonedDate;

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

public class ZonedDateDeserializer extends StdDeserializer<ZonedDate> implements ContextualDeserializer {

    private final DateTimeFormatter formatter;

    protected ZonedDateDeserializer() {
        this(DateTimeFormatters.DATE.withZone(DateTimeUtils.ZONE_PL));
    }

    public ZonedDateDeserializer(DateTimeFormatter formatter) {
        super(ZonedDate.class);
        this.formatter = formatter;
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext serializers, BeanProperty property) throws JsonMappingException {
        JsonFormat.Value format = findFormatOverrides(serializers, property, handledType());
        if (format == null) {
            return this;
        }

        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 ZonedDateDeserializer(formatter2);
    }

    @Override
    public ZonedDate deserialize(JsonParser parser,
        DeserializationContext context) throws IOException, JacksonException {
        if (parser.hasTokenId(JsonTokenId.ID_STRING)) {
            return DateTimeParsers.parseDate(formatter, formatter.getZone(), parser.getText());
        }
        if (parser.hasTokenId(JsonTokenId.ID_NUMBER_INT)) {
            int seconds = parser.getNumberValueExact().intValue();
            return ZonedDate.ofEpochSecond(formatter.getZone(), seconds);
        }
        throw JsonMappingException.from(parser, "Invalid date: " + parser.getValueAsString());
    }

}
