package io.delphi.qa.auto.awsmfrw.models;

import io.delphi.qa.auto.awsmfrw.common_baby.ICanProvideHelpers;
import io.delphi.qa.auto.awsmfrw.common_baby.ICanProvideResources;
import io.delphi.qa.auto.awsmfrw.common_baby.IsaCommonMethods;
import io.delphi.qa.auto.awsmfrw.common_baby.exceptions.FeatureNotImplementedException;
import io.delphi.qa.auto.awsmfrw.suppliers.DelphiDataContainer;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public interface ICanFetch {

  static String fetchItem(ICanProvideResources item) {
    return IsaCommonMethods.chooseRandom(fetchItems(item));
  }

  static Set<String> fetchItems(ICanProvideResources item) {
    return IsaCommonMethods.pullResourceDataItems(
        item, Objects::nonNull, INT_DEFAULT_IDS_LIMIT);
  }

  default ICanProvideResources getDefaultTopItem(){
    throw new FeatureNotImplementedException("'config_key' top item not implemented.");
  }

  int INT_DEFAULT_IDS_LIMIT = 20; // rest params max limit == 50 items per param

  default Object fetchResourceItems(ICanProvideResources resourceItem) {
    return DelphiDataContainer.fetchResources(resourceItem);
  }

  static Object pullResourceItems(ICanProvideResources resourceItem) {
    return DelphiDataContainer.fetchResources(resourceItem);
  }

  default Set<String> fetchResourceDataItems(
      ICanProvideResources resourceItem, Predicate<String> predicate, int limit) {
    return verifyLimit(
        new HashSet<>((List<String>) DelphiDataContainer.fetchResources(resourceItem))
            .stream().filter(predicate).collect(Collectors.toSet()),
        limit);
  }

  default <T> T randomItem(Set<T> items) {
    int nextInt = IsaCommonMethods.random.nextInt(items.size());
    return items.size() > 1 ? (T) items.toArray()[nextInt] : items.iterator().next();
  }

  default Set<String> randomSubItems(Set<String> items) {
    return items.stream()
        .collect(
            Collectors.collectingAndThen(
                Collectors.toList(),
                collected -> {
                  Collections.shuffle(collected);
                  return collected.stream();
                }))
        .limit(items.size())
        .collect(Collectors.toSet());
  }

  default Set<String> verifyLimit(Set<String> set, Integer limit) {
    return limit == null ? set : set.stream().limit(limit).collect(Collectors.toSet());
  }

  default Object fetchHelper(ICanProvideHelpers helper) {
    return DelphiDataContainer.fetchHelperItem(helper);
  }
}
