package ru.yandex.qe.dispenser.ws.quota.request;

import java.util.List;
import java.util.Set;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import ru.yandex.qe.dispenser.api.v1.DiAmount;
import ru.yandex.qe.dispenser.domain.exception.SingleMessageException;
import ru.yandex.qe.dispenser.domain.util.ValidationUtils;

public class SetResourceAmountBody {

    private final List<Item> updates;

    @JsonCreator
    public SetResourceAmountBody(@Nullable @JsonProperty("updates") final List<Item> updates) {
        this.updates = ValidationUtils.requireNonNull(updates, "Updates must be non-null");
    }

    public List<Item> getUpdates() {
        return updates;
    }

    @Override
    public String toString() {
        return "SetResourceAmountBody{" +
                "updates=" + updates +
                '}';
    }

    public static class Item {
        private final Long requestId;
        private final String ticketKey;
        private final List<ChangeBody> changes;
        private final String comment;

        @JsonCreator
        public Item(@Nullable @JsonProperty("requestId") final Long requestId,
                    @Nullable @JsonProperty("ticketKey") final String ticketKey,
                    @Nullable @JsonProperty("changes") final List<ChangeBody> changes,
                    @Nullable @JsonProperty("comment") final String comment) {
            if (requestId == null && ticketKey == null) {
                throw SingleMessageException.illegalArgument("request.id.or.ticket.key.required");
            }
            if (requestId != null && ticketKey != null) {
                throw SingleMessageException.illegalArgument("request.id.and.ticket.key.together");
            }
            this.requestId = requestId;
            this.ticketKey = ticketKey;
            this.changes = ValidationUtils.requireNonNull(changes, "Changes must be non-null");
            this.comment = comment;
        }

        public Long getRequestId() {
            return requestId;
        }

        public List<ChangeBody> getChanges() {
            return changes;
        }

        public String getComment() {
            return comment;
        }

        public String getTicketKey() {
            return ticketKey;
        }

        @Override
        public String toString() {
            return "Item{" +
                    "requestId=" + requestId +
                    ", changes=" + changes +
                    ", comment='" + comment + '\'' +
                    '}';
        }
    }

    public static class ChangeBody {
        @Nullable
        private final String serviceKey;
        @Nullable
        private final Long bigOrderId;
        @NotNull
        private final String resourceKey;
        @NotNull
        private final Set<String> segmentKeys;
        @Nullable
        private final DiAmount amountReady;
        @Nullable
        private final DiAmount amountAllocated;

        @JsonCreator
        public ChangeBody(@Nullable @JsonProperty("serviceKey") final String serviceKey,
                          @Nullable @JsonProperty("bigOrderId") final Long bigOrderId,
                          @Nullable @JsonProperty("resourceKey") final String resourceKey,
                          @Nullable @JsonProperty("segmentKeys") final Set<String> segmentKeys,
                          @Nullable @JsonProperty("amountReady") final DiAmount amountReady,
                          @Nullable @JsonProperty("amountAllocated") final DiAmount amountAllocated
        ) {
            this.serviceKey = serviceKey;
            this.bigOrderId = bigOrderId;
            this.resourceKey = ValidationUtils.requireNonNull(resourceKey, "Resource key must be non-null");
            this.segmentKeys = ValidationUtils.requireNonNull(segmentKeys, "Segments must be non-null");
            this.amountReady = amountReady;
            this.amountAllocated = amountAllocated;
        }

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

        @Nullable
        public Long getBigOrderId() {
            return bigOrderId;
        }

        @NotNull
        public String getResourceKey() {
            return resourceKey;
        }

        @NotNull
        public Set<String> getSegmentKeys() {
            return segmentKeys;
        }

        @Nullable
        @JsonSerialize(using = DiAmount.CompactSerializer.class)
        public DiAmount getAmountReady() {
            return amountReady;
        }

        @Nullable
        @JsonSerialize(using = DiAmount.CompactSerializer.class)
        public DiAmount getAmountAllocated() {
            return amountAllocated;
        }

        @JsonIgnore
        public boolean isEmpty() {
            return amountReady == null && amountAllocated == null;
        }

        @Override
        public String toString() {
            return "ChangeBody{" +
                    "resourceKey='" + resourceKey + '\'' +
                    ", segmentKeys=" + segmentKeys +
                    ", amountReady=" + amountReady +
                    ", amountAllocated=" + amountAllocated +
                    '}';
        }
    }

}
