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

import java.util.Collection;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Stream;

import javax.annotation.ParametersAreNonnullByDefault;

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

import ru.yandex.qe.dispenser.domain.abc.AbcApi;
import ru.yandex.qe.dispenser.domain.abc.Page;
import ru.yandex.qe.dispenser.ws.TvmDestination;

@ParametersAreNonnullByDefault
abstract class PageRequestBuilder<T, B extends PageRequestBuilder<T, B>>
        implements BasePageRequestBuilder<T, B> {

    @NotNull
    protected final AbcApi abcApi;
    @NotNull
    protected TvmDestination abcTvmDestination;
    @Nullable
    protected Integer page;
    @Nullable
    protected Integer pageSize = AbcApi.MAX_PAGE_SIZE;
    @Nullable
    protected Set<String> fields;
    @Nullable
    protected String ids;

    protected PageRequestBuilder(final AbcApi abcApi, final TvmDestination abcTvmDestination) {
        this.abcApi = abcApi;
        this.abcTvmDestination = abcTvmDestination;
    }

    @Override
    @Nullable
    public String getFields() {
        return join(fields);
    }

    @Override
    @NotNull
    public B fields(@NotNull final Set<String> fields) {
        this.fields = fields;
        return self();
    }

    @Override
    @NotNull
    public B ids(@NotNull final Collection<Integer> ids) {
        this.ids = join(ids);
        return self();
    }

    @NotNull
    protected B page(@Nullable final Integer page) {
        this.page = page;
        return self();
    }

    @Override
    @NotNull
    public B pageSize(@NotNull final Integer pageSize) {
        this.pageSize = pageSize;
        return self();
    }

    @Override
    @NotNull
    public Page<T> perform() {
        Objects.requireNonNull(abcTvmDestination);
        return abcTvmDestination.runAuthorized(this::execute);
    }

    @Override
    @NotNull
    public Stream<T> stream() {
        return new PageIterator<>(self()).stream();
    }

    @SuppressWarnings("unchecked")
    @NotNull
    protected B self() {
        return (B) this;
    }

    @NotNull
    protected abstract Page<T> execute();
}
