package com.n3plugins.guardiansrift;

import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

final class GuardiansRiftAltarSelector
{
    private GuardiansRiftAltarSelector()
    {
    }

    static Optional<GuardiansRiftAltar> choose(List<GuardiansRiftAltarCandidate> candidates,
                                               GuardiansRiftAltarContext context)
    {
        List<GuardiansRiftAltarCandidate> accessible = candidates.stream()
                .filter(GuardiansRiftAltarCandidate::canEnter)
                .filter(candidate -> context.canUse(candidate.getAltar()))
                .collect(Collectors.toList());
        if (accessible.isEmpty())
        {
            return Optional.empty();
        }

        boolean allIgnored = accessible.stream().allMatch(candidate -> context.isIgnored(candidate.getAltar()));
        if (!allIgnored)
        {
            accessible = accessible.stream()
                    .filter(candidate -> !context.isIgnored(candidate.getAltar()))
                    .collect(Collectors.toList());
        }

        if (context.isPrioritizeBloodDeath())
        {
            Optional<GuardiansRiftAltarCandidate> bloodDeath = accessible.stream()
                    .filter(candidate -> candidate.getAltar().isBloodOrDeath())
                    .max(candidateOrder());
            if (bloodDeath.isPresent())
            {
                return Optional.of(bloodDeath.get().getAltar());
            }
        }

        Optional<GuardiansRiftAltarCandidate> elemental = best(accessible, false);
        Optional<GuardiansRiftAltarCandidate> catalytic = best(accessible, true);
        if (elemental.isEmpty())
        {
            return catalytic.map(GuardiansRiftAltarCandidate::getAltar);
        }
        if (catalytic.isEmpty())
        {
            return elemental.map(GuardiansRiftAltarCandidate::getAltar);
        }
        if (context.getCatalyticPoints() > context.getElementalPoints())
        {
            return elemental.map(GuardiansRiftAltarCandidate::getAltar);
        }
        return catalytic.map(GuardiansRiftAltarCandidate::getAltar);
    }

    private static Optional<GuardiansRiftAltarCandidate> best(List<GuardiansRiftAltarCandidate> candidates,
                                                             boolean catalytic)
    {
        return candidates.stream()
                .filter(candidate -> candidate.getAltar().isCatalytic() == catalytic)
                .max(candidateOrder());
    }

    private static Comparator<GuardiansRiftAltarCandidate> candidateOrder()
    {
        return Comparator
                .comparingInt((GuardiansRiftAltarCandidate candidate) -> candidate.getAltar().getPriority())
                .thenComparing(GuardiansRiftAltarCandidate::hasTalisman);
    }
}
