package ru.yandex.qe.dispenser.api.v1.request;

import java.io.IOException;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import ru.yandex.qe.dispenser.api.util.JsonDeserializerBase;
import ru.yandex.qe.dispenser.api.util.JsonSerializerBase;
import ru.yandex.qe.dispenser.api.util.ValidationUtils;

@JsonSerialize(using = DiServiceEntityReference.Serializer.class)
@JsonDeserialize(using = DiServiceEntityReference.Deserializer.class)
public class DiServiceEntityReference extends DiEntityReference {
    @NotNull
    private final String serviceKey;

    protected DiServiceEntityReference(@NotNull final Builder builder) {
        super(builder);
        this.serviceKey = ValidationUtils.requireNonNull(builder.serviceKey, "Service key is required!");
    }

    @NotNull
    public static Builder withKey(@NotNull final String entityKey) {
        return new Builder(entityKey);
    }

    @NotNull
    public String getServiceKey() {
        return serviceKey;
    }

    @Override
    public boolean equals(@Nullable final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        return super.equals(o) && serviceKey.equals(((DiServiceEntityReference) o).serviceKey);
    }

    @Override
    public int hashCode() {
        return 31 * super.hashCode() + serviceKey.hashCode();
    }

    public static class Builder extends DiEntityReference.Builder {
        @Nullable
        private String serviceKey;

        public Builder(@NotNull final String key) {
            super(key);
        }

        @NotNull
        @Override
        public Builder bySpecification(@NotNull final String specificationKey) {
            super.bySpecification(specificationKey);
            return this;
        }

        public Builder inService(@NotNull final String serviceKey) {
            this.serviceKey = serviceKey;
            return this;
        }

        @NotNull
        @Override
        public DiServiceEntityReference build() {
            return new DiServiceEntityReference(this);
        }
    }

    static final class Serializer extends JsonSerializerBase<DiServiceEntityReference> {
        @Override
        public void serialize(@NotNull final DiServiceEntityReference entity,
                              @NotNull final JsonGenerator jg,
                              @NotNull final SerializerProvider sp) throws IOException {
            jg.writeStartObject();
            jg.writeStringField("key", entity.getKey());
            jg.writeStringField("specificationKey", entity.getSpecificationKey());
            jg.writeStringField("serviceKey", entity.getServiceKey());
            jg.writeEndObject();
        }
    }

    static final class Deserializer extends JsonDeserializerBase<DiServiceEntityReference> {
        @NotNull
        @Override
        public DiServiceEntityReference deserialize(final @NotNull JsonParser jp,
                                                    final @NotNull DeserializationContext dc) throws IOException {
            final JsonNode json = toJson(jp);
            return withKey(json.get("key").asText())
                    .bySpecification(json.get("specificationKey").asText())
                    .inService(json.get("serviceKey").asText())
                    .build();
        }
    }
}
