package ru.yandex.qe.dispenser.ws.reqbody;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.jetbrains.annotations.NotNull;

/**
 * Request quota allocation for service with Accounts body.
 *
 * @author Ruslan Kadriev <aqru@yandex-team.ru>
 */
@JsonIgnoreProperties(ignoreUnknown = true)
public class RequestQuotaAllocationBody {
    @NotNull
    private final List<Change> changes;

    @JsonCreator
    public RequestQuotaAllocationBody(
            @JsonProperty(value = "changes", required = true) @NotNull List<Change> changes
    ) {
        this.changes = changes;
    }

    @NotNull
    public List<Change> getChanges() {
        return changes;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        RequestQuotaAllocationBody that = (RequestQuotaAllocationBody) o;
        return changes.equals(that.changes);
    }

    @Override
    public int hashCode() {
        return Objects.hash(changes);
    }

    @Override
    public String toString() {
        return "RequestQuotaAllocationBody{" +
                "changes=" + changes +
                '}';
    }

    public static Builder builder() {
        return new Builder();
    }

    public static class Builder {
        private List<Change> changes = new ArrayList<>();

        public Builder change(Change change) {
            changes.add(change);
            return this;
        }

        public Builder changes(List<Change> changes) {
            this.changes = changes;
            return this;
        }

        public RequestQuotaAllocationBody build() {
            return new RequestQuotaAllocationBody(
                    Objects.requireNonNull(changes, "Changes is required!")
            );
        }
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class Change {
        @NotNull
        private final String resourceKey;
        private final long orderId;
        @NotNull
        private final Set<String> segmentKeys;
        @NotNull
        private final String accountId;
        @NotNull
        private final String folderId;
        @NotNull
        private final String providerId;

        @JsonCreator
        public Change(
                @JsonProperty(value = "resourceKey", required = true) @NotNull String resourceKey,
                @JsonProperty(value = "orderId", required = true) long orderId,
                @JsonProperty(value = "segmentKeys", required = true) @NotNull Set<String> segmentKeys,
                @JsonProperty(value = "accountId", required = true) @NotNull String accountId,
                @JsonProperty(value = "folderId", required = true) @NotNull String folderId,
                @JsonProperty(value = "providerId", required = true) @NotNull String providerId) {
            this.resourceKey = resourceKey;
            this.orderId = orderId;
            this.segmentKeys = segmentKeys;
            this.accountId = accountId;
            this.folderId = folderId;
            this.providerId = providerId;
        }

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

        public long getOrderId() {
            return orderId;
        }

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

        @NotNull
        public String getAccountId() {
            return accountId;
        }

        @NotNull
        public String getFolderId() {
            return folderId;
        }

        @NotNull
        public String getProviderId() {
            return providerId;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            Change change = (Change) o;
            return orderId == change.orderId && resourceKey.equals(change.resourceKey)
                    && segmentKeys.equals(change.segmentKeys) && accountId.equals(change.accountId)
                    && folderId.equals(change.folderId) && providerId.equals(change.providerId);
        }

        @Override
        public int hashCode() {
            return Objects.hash(resourceKey, orderId, segmentKeys, accountId, folderId, providerId);
        }

        @Override
        public String toString() {
            return "Change{" +
                    "resourceKey='" + resourceKey + '\'' +
                    ", orderId=" + orderId +
                    ", segmentKeys=" + segmentKeys +
                    ", accountId='" + accountId + '\'' +
                    ", folderId='" + folderId + '\'' +
                    ", providerId='" + providerId + '\'' +
                    '}';
        }

        public static Builder build() {
            return new Builder();
        }

        public static class Builder {
            private String resourceKey;
            private long orderId;
            private Set<String> segmentKeys = new HashSet<>();
            private String accountId;
            private String folderId;
            private String providerId;

            public Builder resourceKey(String resourceKey) {
                this.resourceKey = resourceKey;
                return this;
            }

            public Builder orderId(long orderId) {
                this.orderId = orderId;
                return this;
            }

            public Builder segmentKey(String segmentKey) {
                segmentKeys.add(segmentKey);
                return this;
            }

            public Builder segmentKeys(Set<String> segmentKeys) {
                this.segmentKeys = segmentKeys;
                return this;
            }

            public Builder accountId(String accountId) {
                this.accountId = accountId;
                return this;
            }

            public Builder folderId(String folderId) {
                this.folderId = folderId;
                return this;
            }

            public Builder providerId(String providerId) {
                this.providerId = providerId;
                return this;
            }

            public Change build() {
                return new Change(
                        Objects.requireNonNull(resourceKey, "ResourceKey is required!"),
                        orderId,
                        Objects.requireNonNull(segmentKeys, "SegmentKeys is required!"),
                        Objects.requireNonNull(accountId, "AccountId is required!"),
                        Objects.requireNonNull(folderId, "FolderId is required!"),
                        Objects.requireNonNull(providerId, "ProviderId is required!")
                );
            }
        }
    }
}
