package ru.yandex.qe.dispenser.domain.dao.bot.service.reserve.configurations;

import ru.yandex.qe.dispenser.api.v1.DiBotConfigurationReserve;
import ru.yandex.qe.dispenser.domain.Service;
import ru.yandex.qe.dispenser.domain.dao.bot.service.reserve.BotReserve;
import ru.yandex.qe.dispenser.domain.hierarchy.Hierarchy;
import ru.yandex.qe.dispenser.domain.index.LongIndexBase;

import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Objects;

@ParametersAreNonnullByDefault
public class BotConfigurationReserve extends LongIndexBase implements BotReserve {

    private final Key key;
    private final long quantity;
    private final Long storageQuantity;

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

    public BotConfigurationReserve(final Key key, final long quantity, Long storageQuantity) {
        this.key = key;
        this.quantity = quantity;
        this.storageQuantity = storageQuantity;
    }

    private BotConfigurationReserve(final Builder builder) {
        this(new Key(builder), Objects.requireNonNull(builder.quantity, "Quantity is required"), builder.storageQuantity);
        if (builder.id != null) {
            setId(builder.id);
        }
    }

    public Key getKey() {
        return key;
    }

    public long getQuantity() {
        return quantity;
    }

    @Nullable
    public Long getStorageQuantity() {
        return storageQuantity;
    }

    @Override
    public Service getService() {
        return getKey().getService();
    }

    public Builder copyBuilder() {
        return builder()
                .id(getId())
                .campaignId(getKey().getCampaignId())
                .service(getKey().getService())
                .bigOrderId(getKey().getBigOrderId())
                .locationSegmentId(getKey().getLocationSegmentId())
                .configurationId(getKey().getConfigurationId())
                .quantity(getQuantity())
                .storageId(getKey().getStorageId())
                .storageQuantity(getStorageQuantity());
    }

    public DiBotConfigurationReserve toView(final Hierarchy hierarchy) {
        return DiBotConfigurationReserve.builder()
                .id(getId())
                .serviceKey(getKey().getService().getKey())
                .campaignId(getKey().getCampaignId())
                .bigOrderId(getKey().getBigOrderId())
                .locationSegmentKey(hierarchy.getSegmentReader().read(getKey().getLocationSegmentId()).getPublicKey())
                .configurationId(getKey().getConfigurationId())
                .quantity(getQuantity())
                .storageId(getKey().getStorageId())
                .storageQuantity(getStorageQuantity())
                .build();
    }

    public static class Key {
        private final Service service;
        private final long campaignId;
        private final long bigOrderId;
        private final long locationSegmentId;
        private final long configurationId;
        private final Long storageId;

        public Key(final Service service, final long campaignId, final long bigOrderId, final long locationSegmentId, final long configurationId, final Long storageId) {
            this.service = service;
            this.campaignId = campaignId;
            this.bigOrderId = bigOrderId;
            this.locationSegmentId = locationSegmentId;
            this.configurationId = configurationId;
            this.storageId = storageId;
        }

        public Key(final Builder builder) {
            this.service = Objects.requireNonNull(builder.service, "Service is required");
            this.campaignId = Objects.requireNonNull(builder.campaignId, "CampaignId is required");
            this.bigOrderId = Objects.requireNonNull(builder.bigOrderId, "BigOrderId is required");
            this.locationSegmentId = Objects.requireNonNull(builder.locationSegmentId, "LocationSegmentId is required");
            this.configurationId = Objects.requireNonNull(builder.configurationId, "BigOrderConfigId is required");
            this.storageId = builder.storageId;
        }

        public Service getService() {
            return service;
        }

        public long getCampaignId() {
            return campaignId;
        }

        public long getBigOrderId() {
            return bigOrderId;
        }

        public long getLocationSegmentId() {
            return locationSegmentId;
        }

        public long getConfigurationId() {
            return configurationId;
        }

        public Long getStorageId() {
            return storageId;
        }

        @Override
        public boolean equals(final Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            final Key key = (Key) o;
            return service == key.service &&
                    campaignId == key.campaignId &&
                    bigOrderId == key.bigOrderId &&
                    locationSegmentId == key.locationSegmentId &&
                    configurationId == key.configurationId &&
                    Objects.equals(storageId, key.storageId);
        }

        @Override
        public int hashCode() {
            return Objects.hash(service, campaignId, bigOrderId, locationSegmentId, configurationId, storageId);
        }

        @Override
        public String toString() {
            return "Key{" +
                    "service=" + service +
                    ", campaignId=" + campaignId +
                    ", bigOrderId=" + bigOrderId +
                    ", locationSegmentId=" + locationSegmentId +
                    ", configurationId=" + configurationId +
                    ", storageId=" + storageId +
                    '}';
        }
    }

    public static class Builder {
        private Long id;
        private Service service;
        private Long campaignId;
        private Long bigOrderId;
        private Long locationSegmentId;
        private Long configurationId;
        private Long storageId;
        private Long quantity;
        private Long storageQuantity;

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

        public Builder service(final Service service) {
            this.service = service;
            return this;
        }

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

        public Builder bigOrderId(final Long bigOrderId) {
            this.bigOrderId = bigOrderId;
            return this;
        }

        public Builder locationSegmentId(final Long locationSegmentId) {
            this.locationSegmentId = locationSegmentId;
            return this;
        }

        public Builder configurationId(final Long configurationId) {
            this.configurationId = configurationId;
            return this;
        }

        public Builder quantity(final Long quantity) {
            this.quantity = quantity;
            return this;
        }

        public Builder storageId(@Nullable final Long storageId) {
            this.storageId = storageId;
            return this;
        }

        public Builder storageQuantity(@Nullable final Long storageQuantity) {
            this.storageQuantity = storageQuantity;
            return this;
        }

        public BotConfigurationReserve build() {
            return new BotConfigurationReserve(this);
        }
    }

}
