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

import java.util.Collection;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.ws.rs.QueryParam;

import com.google.common.base.Suppliers;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import ru.yandex.qe.dispenser.api.v1.field.DiField;

public abstract class FieldsParam implements Supplier<Set<DiField<?>>> {
    public static final String FIELDS_PARAM = "fields";
    public static final String FIELD_PARAM = "field";

    @Nullable
    @QueryParam("fields")
    private String fieldsString;
    @Nullable
    @QueryParam("field")
    private Set<String> fieldParams;

    public FieldsParam(@Nullable final String fieldsString, @Nullable final Set<String> fieldParams) {
        this.fieldsString = fieldsString;
        this.fieldParams = fieldParams;
    }

    private final Supplier<Set<DiField<?>>> filedNamesSupplier = Suppliers.memoize(this::computeFieldNames)::get;

    @Override
    @NotNull
    public Set<DiField<?>> get() {
        return filedNamesSupplier.get();
    }

    public boolean isEmpty() {
        return get().isEmpty();
    }

    @NotNull
    private Set<DiField<?>> computeFieldNames() {
        final Stream<String> fromFieldsString = Optional.ofNullable(fieldsString)
                .filter(StringUtils::isNotBlank)
                .map(s -> Stream.of(StringUtils.split(s, ",")).map(String::trim))
                .orElse(Stream.empty());

        final Stream<String> fromFieldParam = Optional.ofNullable(fieldParams)
                .map(Collection::stream)
                .orElse(Stream.empty());

        return Stream.concat(fromFieldsString, fromFieldParam)
                .map(this::getFieldByKey)
                .collect(Collectors.toSet());
    }

    @NotNull
    protected abstract DiField<?> getFieldByKey(final String key);
}
