package solitaire;

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

final class Depot {
    private static boolean isValidNextCard(Card lastCard, Card nextCard) {
	if (nextCard.getSuit().isRed() == lastCard.getSuit().isRed())
	    return false;

	return lastCard.getRank().isSuccessorOf(nextCard.getRank());
    }

    private static boolean isValidRun(List<Card> run) {
	Card prev = null;

	for (Card next : run) {
	    if (next.isHidden() || (prev != null && !isValidNextCard(prev, next)))
		return false;

	    prev = next;
	}

	return true;
    }

    private final List<Card> cards;

    Depot(List<Card> cards) {
	if (cards.isEmpty())
	    throw new IllegalArgumentException("Depot should be initialized with at least one card");

	this.cards = new LinkedList<>(cards);
	this.cards.getLast().reveal();
    }

    @Override
    public String toString() {
	if (cards.isEmpty())
	    return "<   >";

	return cards.stream().map(String::valueOf).collect(Collectors.joining("\n"));
    }

    private boolean isValidPlacement(Card card) {
	if (cards.isEmpty())
	    return card.getRank() == Rank.KING;

	return isValidNextCard(cards.getLast(), card);
    }

    boolean add(Card card) {
	return add(List.of(card));
    }

    boolean add(List<Card> run) {
	/*
	 * no invalid run can be generated by the game, so we only need to check
	 * placement.
	 */
	if (!isValidPlacement(run.getFirst()))
	    return false;

	cards.addAll(run);
	return true;
    }

    Optional<List<Card>> remove(int size) {
	if (size < 1)
	    throw new IllegalArgumentException("Size must be a positive integer");

	if (cards.size() < size)
	    return Optional.empty();

	List<Card> slice = cards.subList(cards.size() - size, cards.size());

	if (!isValidRun(slice))
	    return Optional.empty();

	List<Card> run = List.copyOf(slice);
	slice.clear();

	if (!cards.isEmpty())
	    cards.getLast().reveal();

	return Optional.of(run);
    }
}
