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

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

import org.jetbrains.annotations.NotNull;

import ru.yandex.qe.dispenser.domain.QuotaChangeRequest;
import ru.yandex.qe.dispenser.domain.util.Errors;
import ru.yandex.qe.dispenser.ws.allocation.AllocationError;

/**
 * Request quota allocation from service with account validated body.
 *
 * @author Ruslan Kadriev <aqru@yandex-team.ru>
 */
public class RequestQuotaValidatedBody {
    @NotNull
    private final List<Change> changes;
    @NotNull
    private final Errors<AllocationError> validationErrors;

    public RequestQuotaValidatedBody(@NotNull List<Change> changes,
                                     @NotNull Errors<AllocationError> validationErrors) {
        this.changes = changes;
        this.validationErrors = validationErrors;
    }

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

    @NotNull
    public Errors<AllocationError> getValidationErrors() {
        return validationErrors;
    }

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

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

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

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

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

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

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

        public Builder error(AllocationError error) {
            validationErrors.add(error);
            return this;
        }

        public Builder errors(Errors<AllocationError> validationErrors) {
            this.validationErrors.add(validationErrors);
            return this;
        }

        public RequestQuotaValidatedBody build() {
            return new RequestQuotaValidatedBody(
                    Objects.requireNonNull(changes),
                    validationErrors);
        }
    }

    public static class Change {
        @NotNull
        private final QuotaChangeRequest.Change change;
        @NotNull
        private final String accountId;
        @NotNull
        private final String folderId;
        @NotNull
        private final String providerId;

        public Change(@NotNull QuotaChangeRequest.Change change,
                      @NotNull String accountId,
                      @NotNull String folderId,
                      @NotNull String providerId) {
            this.change = change;
            this.accountId = accountId;
            this.folderId = folderId;
            this.providerId = providerId;
        }

        @NotNull
        public QuotaChangeRequest.Change getChange() {
            return change;
        }

        @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 change1 = (Change) o;
            return change.equals(change1.change) && accountId.equals(change1.accountId)
                    && folderId.equals(change1.folderId) && providerId.equals(change1.providerId);
        }

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

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

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

        public static  class  Builder {
            private QuotaChangeRequest.Change change;
            private String accountId;
            private String folderId;
            private String providerId;

            public Builder change(QuotaChangeRequest.Change change) {
                this.change = change;
                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(change, "Change is required!"),
                        Objects.requireNonNull(accountId, "AccountId is required!"),
                        Objects.requireNonNull(folderId, "FolderId is required!"),
                        Objects.requireNonNull(providerId, "ProviderId is required!")
                );
            }
        }
    }
}
