package ru.yandex.qe.dispenser.ws.api.model.distribution;

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.JsonInclude;
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;

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public final class QuotaDistributionRemainder {

    @NotNull
    private final List<Change> changes;

    private QuotaDistributionRemainder(@NotNull final List<Change> changes) {
        this.changes = changes;
    }

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

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

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

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

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

    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    public static final class Change {

        @NotNull
        private final String resourceKey;
        @NotNull
        private final Set<String> segmentKeys;
        @NotNull
        private final DiAmount amountReady;

        private Change(@NotNull final String resourceKey,
                       @NotNull final Set<String> segmentKeys,
                       @NotNull final DiAmount amountReady) {
            this.resourceKey = resourceKey;
            this.segmentKeys = segmentKeys;
            this.amountReady = amountReady;
        }

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

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

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

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

        @Override
        public boolean equals(final Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            final Change change = (Change) o;
            return resourceKey.equals(change.resourceKey) &&
                    segmentKeys.equals(change.segmentKeys) &&
                    Objects.equals(amountReady, change.amountReady);
        }

        @Override
        public int hashCode() {
            return Objects.hash(resourceKey, segmentKeys, amountReady);
        }

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

        public static final class Builder {

            @Nullable
            private String resourceKey;
            @NotNull
            private Set<String> segmentKeys = new HashSet<>();
            @Nullable
            private DiAmount amountReady;

            private Builder() {
            }

            @NotNull
            public Builder resourceKey(@NotNull final String resourceKey) {
                Objects.requireNonNull(resourceKey, "Resource key is required.");
                this.resourceKey = resourceKey;
                return this;
            }

            @NotNull
            public Builder segmentKeys(@NotNull final Set<String> segmentKeys) {
                Objects.requireNonNull(segmentKeys, "Segment keys are required.");
                this.segmentKeys = segmentKeys;
                return this;
            }

            @NotNull
            public Builder amountReady(final DiAmount amountReady) {
                this.amountReady = amountReady;
                return this;
            }

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

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

            @Nullable
            public DiAmount getAmountReady() {
                return amountReady;
            }

            @NotNull
            public Change build() {
                Objects.requireNonNull(resourceKey, "Resource key is required.");
                Objects.requireNonNull(amountReady, "Amount ready is required.");
                return new Change(resourceKey, segmentKeys, amountReady);
            }

            @Override
            public boolean equals(final Object o) {
                if (this == o) {
                    return true;
                }
                if (o == null || getClass() != o.getClass()) {
                    return false;
                }
                final Builder builder = (Builder) o;
                return Objects.equals(resourceKey, builder.resourceKey) &&
                        segmentKeys.equals(builder.segmentKeys) &&
                        Objects.equals(amountReady, builder.amountReady);
            }

            @Override
            public int hashCode() {
                return Objects.hash(resourceKey, segmentKeys, amountReady);
            }

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

    }

    public static final class Builder {

        @NotNull
        private final List<Change> changes = new ArrayList<>();

        private Builder() {
        }

        @NotNull
        public Builder addChange(@NotNull final Change change) {
            Objects.requireNonNull(change, "Change is required.");
            this.changes.add(change);
            return this;
        }

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

        @NotNull
        public QuotaDistributionRemainder build() {
            return new QuotaDistributionRemainder(changes);
        }

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

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

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

    }

}
