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

import java.util.Optional;
import java.util.Set;

import javax.annotation.Nonnull;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import ru.yandex.qe.dispenser.api.v1.DiUnit;
import ru.yandex.qe.dispenser.api.v1.request.DiQuotaState;
import ru.yandex.qe.dispenser.domain.Project;
import ru.yandex.qe.dispenser.domain.Quota;
import ru.yandex.qe.dispenser.domain.QuotaSpec;
import ru.yandex.qe.dispenser.domain.Resource;
import ru.yandex.qe.dispenser.domain.Segment;
import ru.yandex.qe.dispenser.domain.Service;
import ru.yandex.qe.dispenser.domain.dao.segment.SegmentUtils;
import ru.yandex.qe.dispenser.domain.hierarchy.Hierarchy;

public final class QuotaState {
    @Nullable
    private final Long actual;
    @Nullable
    private final Long max;
    @Nullable
    private final Long ownMax;
    @NotNull
    private final Quota.Key quotaKey;

    public static QuotaState from(@Nonnull final DiQuotaState state, @Nonnull final Service service) {
        final Project project = Hierarchy.get().getProjectReader().read(state.getProjectKey());
        final Resource resource = Hierarchy.get().getResourceReader().read(new Resource.Key(state.getResourceKey(), service));
        final QuotaSpec quotaSpec = Hierarchy.get().getQuotaSpecReader().read(resource, state.getQuotaSpecKey());
        final DiUnit baseUnit = resource.getType().getBaseUnit();
        final Long actual = Optional.ofNullable(state.getActual()).map(baseUnit::convert).orElse(null);
        final Long max = Optional.ofNullable(state.getMax()).map(baseUnit::convert).orElse(null);
        final Long ownMax = Optional.ofNullable(state.getOwnMax()).map(baseUnit::convert).orElse(null);
        final Set<Segment> segments = SegmentUtils.getCompleteSegmentSet(resource, state.getSegmentKeys());
        return new QuotaState(new Quota.Key(quotaSpec, project, segments), actual, max, ownMax);
    }

    private QuotaState(@NotNull final Quota.Key quotaKey,
                       @Nullable final Long actual,
                       @Nullable final Long max,
                       @Nullable final Long ownMax) {
        this.quotaKey = quotaKey;
        this.actual = actual;
        this.max = max;
        this.ownMax = ownMax;
    }

    @NotNull
    public Quota.Key getQuotaKey() {
        return quotaKey;
    }

    @Nullable
    public Long getActual() {
        return actual;
    }

    @Nullable
    public Long getMax() {
        return max;
    }

    @Nullable
    public Long getOwnMax() {
        return ownMax;
    }

    public boolean isAggregation() {
        return getQuotaKey().isAggregation();
    }
}
