package ru.yandex.qe.dispenser.domain.resources_model;

import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;

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

public final class QuotaRequestDelivery {

    private final UUID id;
    private final long authorId;
    private final long authorUid;
    private final long abcServiceId;
    private final long quotaRequestId;
    private final long campaignId;
    private final long providerId;
    private final Instant createdAt;
    private final Instant resolvedAt;
    private final boolean resolved;
    private final List<ExternalResource> externalResources;
    private final List<InternalResource> internalResources;
    private final List<DeliveryResult> deliveryResults;
    private final QuotaRequestDeliveryResolveStatus resolveStatus;

    public QuotaRequestDelivery(UUID id,
                                long authorId,
                                long authorUid,
                                long abcServiceId,
                                long quotaRequestId,
                                long campaignId,
                                long providerId,
                                Instant createdAt,
                                Instant resolvedAt,
                                boolean resolved,
                                List<ExternalResource> externalResources,
                                List<InternalResource> internalResources,
                                List<DeliveryResult> deliveryResults,
                                QuotaRequestDeliveryResolveStatus resolveStatus) {
        this.id = id;
        this.authorId = authorId;
        this.authorUid = authorUid;
        this.abcServiceId = abcServiceId;
        this.quotaRequestId = quotaRequestId;
        this.campaignId = campaignId;
        this.providerId = providerId;
        this.createdAt = createdAt;
        this.resolvedAt = resolvedAt;
        this.resolved = resolved;
        this.externalResources = externalResources;
        this.internalResources = internalResources;
        this.deliveryResults = deliveryResults;
        this.resolveStatus = resolveStatus;
    }

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

    public UUID getId() {
        return id;
    }

    public long getAuthorId() {
        return authorId;
    }

    public long getAuthorUid() {
        return authorUid;
    }

    public long getAbcServiceId() {
        return abcServiceId;
    }

    public long getQuotaRequestId() {
        return quotaRequestId;
    }

    public long getCampaignId() {
        return campaignId;
    }

    public long getProviderId() {
        return providerId;
    }

    public Instant getCreatedAt() {
        return createdAt;
    }

    @NotNull
    public Optional<Instant> getResolvedAt() {
        return Optional.ofNullable(resolvedAt);
    }

    public boolean isResolved() {
        return resolved;
    }

    public List<ExternalResource> getExternalResources() {
        return externalResources;
    }

    public List<InternalResource> getInternalResources() {
        return internalResources;
    }

    public List<DeliveryResult> getDeliveryResults() {
        return deliveryResults;
    }

    public QuotaRequestDeliveryResolveStatus getResolveStatus() {
        return resolveStatus;
    }

    public View toView() {
        return new View(getId().toString(), getAuthorId(), getAuthorUid(), getAbcServiceId(), getQuotaRequestId(),
                getCampaignId(), getProviderId(), getCreatedAt().toString(),
                getResolvedAt().map(Instant::toString).orElse(null), isResolved(), getExternalResources(),
                getInternalResources(), getDeliveryResults(), getResolveStatus());
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        QuotaRequestDelivery that = (QuotaRequestDelivery) o;
        return authorId == that.authorId && authorUid == that.authorUid && abcServiceId == that.abcServiceId
                && quotaRequestId == that.quotaRequestId && campaignId == that.campaignId
                && providerId == that.providerId && resolved == that.resolved && Objects.equals(id, that.id)
                && Objects.equals(createdAt, that.createdAt) && Objects.equals(resolvedAt, that.resolvedAt)
                && Objects.equals(externalResources, that.externalResources)
                && Objects.equals(internalResources, that.internalResources)
                && Objects.equals(deliveryResults, that.deliveryResults) && resolveStatus == that.resolveStatus;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, authorId, authorUid, abcServiceId, quotaRequestId, campaignId, providerId, createdAt,
                resolvedAt, resolved, externalResources, internalResources, deliveryResults, resolveStatus);
    }

    @Override
    public String toString() {
        return "QuotaRequestDelivery{" +
                "id=" + id +
                ", authorId=" + authorId +
                ", authorUid=" + authorUid +
                ", abcServiceId=" + abcServiceId +
                ", quotaRequestId=" + quotaRequestId +
                ", campaignId=" + campaignId +
                ", providerId=" + providerId +
                ", createdAt=" + createdAt +
                ", resolvedAt=" + resolvedAt +
                ", resolved=" + resolved +
                ", externalResources=" + externalResources +
                ", internalResources=" + internalResources +
                ", deliveryResults=" + deliveryResults +
                ", resolveStatus=" + resolveStatus +
                '}';
    }

    public Builder toBuilder() {
        return new Builder(this);
    }

    public static final class Builder {

        private List<ExternalResource> externalResources = new ArrayList<>();
        private List<InternalResource> internalResources = new ArrayList<>();
        private List<DeliveryResult> deliveryResults = new ArrayList<>();

        private UUID id;
        private Long authorId;
        private Long authorUid;
        private Long abcServiceId;
        private Long quotaRequestId;
        private Long campaignId;
        private Long providerId;
        private Instant createdAt;
        private Instant resolvedAt;
        private Boolean resolved;
        private QuotaRequestDeliveryResolveStatus resolveStatus;

        private Builder() {
        }

        public Builder(QuotaRequestDelivery quotaRequestDelivery) {
            this.id = quotaRequestDelivery.id;
            this.authorId = quotaRequestDelivery.authorId;
            this.authorUid = quotaRequestDelivery.authorUid;
            this.abcServiceId = quotaRequestDelivery.abcServiceId;
            this.quotaRequestId = quotaRequestDelivery.quotaRequestId;
            this.campaignId = quotaRequestDelivery.campaignId;
            this.providerId = quotaRequestDelivery.providerId;
            this.createdAt = quotaRequestDelivery.createdAt;
            this.resolvedAt = quotaRequestDelivery.resolvedAt;
            this.resolved = quotaRequestDelivery.resolved;
            this.externalResources.addAll(quotaRequestDelivery.externalResources);
            this.internalResources.addAll(quotaRequestDelivery.internalResources);
            this.deliveryResults.addAll(quotaRequestDelivery.deliveryResults);
            this.resolveStatus = quotaRequestDelivery.resolveStatus;
        }

        public Builder id(UUID id) {
            this.id = id;
            return this;
        }

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

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

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

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

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

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

        public Builder createdAt(Instant createdAt) {
            this.createdAt = createdAt;
            return this;
        }

        public Builder resolvedAt(Instant resolvedAt) {
            this.resolvedAt = resolvedAt;
            return this;
        }

        public Builder resolved(boolean resolved) {
            this.resolved = resolved;
            return this;
        }

        public Builder addExternalResource(ExternalResource externalResource) {
            this.externalResources.add(externalResource);
            return this;
        }

        public Builder addExternalResources(Collection<? extends ExternalResource> externalResources) {
            this.externalResources.addAll(externalResources);
            return this;
        }

        public Builder addInternalResource(InternalResource internalResource) {
            this.internalResources.add(internalResource);
            return this;
        }

        public Builder addInternalResources(Collection<? extends InternalResource> internalResources) {
            this.internalResources.addAll(internalResources);
            return this;
        }

        public Builder addDeliveryResult(DeliveryResult deliveryResult) {
            this.deliveryResults.add(deliveryResult);
            return this;
        }

        public Builder addDeliveryResults(Collection<? extends DeliveryResult> deliveryResults) {
            this.deliveryResults.addAll(deliveryResults);
            return this;
        }

        public Builder setExternalResources(List<ExternalResource> externalResources) {
            if (externalResources != null) {
                this.externalResources = externalResources;
            }
            return this;
        }

        public Builder setInternalResources(List<InternalResource> internalResources) {
            if (internalResources != null) {
                this.internalResources = internalResources;
            }
            return this;
        }

        public Builder setDeliveryResults(List<DeliveryResult> deliveryResults) {
            if (deliveryResults != null) {
                this.deliveryResults = deliveryResults;
            }
            return this;
        }

        public Builder resolveStatus(QuotaRequestDeliveryResolveStatus resolveStatus) {
            this.resolveStatus = resolveStatus;
            return this;
        }

        public QuotaRequestDelivery build() {
            Objects.requireNonNull(id, "Id is required");
            Objects.requireNonNull(authorId, "AuthorId is required");
            Objects.requireNonNull(authorUid, "AuthorUid is required");
            Objects.requireNonNull(abcServiceId, "ServiceId is required");
            Objects.requireNonNull(quotaRequestId, "QuotaRequestId is required");
            Objects.requireNonNull(campaignId, "CampaignId is required");
            Objects.requireNonNull(providerId, "ProviderId is required");
            Objects.requireNonNull(createdAt, "CreatedAt is required");
            return new QuotaRequestDelivery(id, authorId, authorUid, abcServiceId, quotaRequestId, campaignId,
                    providerId, createdAt, resolvedAt, resolved, externalResources, internalResources,
                    deliveryResults,
                    Objects.requireNonNull(resolveStatus, "ResolveStatus is required!"));
        }

    }

    public static class View {
        private final String id;
        private final long authorId;
        private final long authorUid;
        private final long abcServiceId;
        private final long quotaRequestId;
        private final long campaignId;
        private final long providerId;
        private final String createdAt;
        private final String resolvedAt;
        private final boolean resolved;
        private final List<ExternalResource> externalResources;
        private final List<InternalResource> internalResources;
        private final List<DeliveryResult> deliveryResults;
        private final QuotaRequestDeliveryResolveStatus resolveStatus;

        @JsonCreator
        public View(@JsonProperty("id") String id,
                    @JsonProperty("authorId") long authorId,
                    @JsonProperty("authorUid") long authorUid,
                    @JsonProperty("abcServiceId") long abcServiceId,
                    @JsonProperty("quotaRequestId") long quotaRequestId,
                    @JsonProperty("campaignId") long campaignId,
                    @JsonProperty("providerId") long providerId,
                    @JsonProperty("createdAt") String createdAt,
                    @JsonProperty("resolvedAt") String resolvedAt,
                    @JsonProperty("resolved") boolean resolved,
                    @JsonProperty("externalResources") List<ExternalResource> externalResources,
                    @JsonProperty("internalResources") List<InternalResource> internalResources,
                    @JsonProperty("deliveryResults") List<DeliveryResult> deliveryResults,
                    @JsonProperty("resolveStatus") QuotaRequestDeliveryResolveStatus resolveStatus) {
            this.id = id;
            this.authorId = authorId;
            this.authorUid = authorUid;
            this.abcServiceId = abcServiceId;
            this.quotaRequestId = quotaRequestId;
            this.campaignId = campaignId;
            this.providerId = providerId;
            this.createdAt = createdAt;
            this.resolvedAt = resolvedAt;
            this.resolved = resolved;
            this.externalResources = externalResources;
            this.internalResources = internalResources;
            this.deliveryResults = deliveryResults;
            this.resolveStatus = resolveStatus;
        }

        public String getId() {
            return id;
        }

        public long getAuthorId() {
            return authorId;
        }

        public long getAuthorUid() {
            return authorUid;
        }

        public long getAbcServiceId() {
            return abcServiceId;
        }

        public long getQuotaRequestId() {
            return quotaRequestId;
        }

        public long getCampaignId() {
            return campaignId;
        }

        public long getProviderId() {
            return providerId;
        }

        public String getCreatedAt() {
            return createdAt;
        }

        public String getResolvedAt() {
            return resolvedAt;
        }

        public boolean isResolved() {
            return resolved;
        }

        public List<ExternalResource> getExternalResources() {
            return externalResources;
        }

        public List<InternalResource> getInternalResources() {
            return internalResources;
        }

        public List<DeliveryResult> getDeliveryResults() {
            return deliveryResults;
        }

        public QuotaRequestDeliveryResolveStatus getResolveStatus() {
            return resolveStatus;
        }
    }

}
