namespace YatzyLibrary
{
    public class YatzyCheckers
    {
        public CheckOutput SingleThingy(List<int> dices, int valueToCheckFor)
        {
            var total = dices.Where(x => x.Equals(valueToCheckFor)).Sum();

            return new CheckOutput()
            {
                success = true,
                value = total
            };
        }

        public CheckOutput PairChecker(List<int> dices, int pairs)
        {
            var counts = new Dictionary<int, int>();
            foreach (var die in dices)
            {
                if (counts.ContainsKey(die))
                    counts[die]++;
                else
                    counts[die] = 1;
            }

            var pairValues = new List<int>();
            foreach (var kvp in counts)
            {
                if (kvp.Value >= 2)
                {
                    pairValues.Add(kvp.Key);
                }
            }

            pairValues.Sort();
            pairValues.Reverse();

            bool success = pairValues.Count >= pairs;
            int sum = 0;

            if (success)
            {
                for (int i = 0; i < pairs && i < pairValues.Count; i++)
                {
                    sum += pairValues[i] * 2;
                }
            }

            return new CheckOutput(success, sum);
        }

        public CheckOutput SameNumberChecker(List<int> dices, int pairs)
        {
            dices.Sort();
            dices.Reverse();
            if (pairs == 3)
            {
                for (int i = 2; i < dices.Count; i++)
                {
                    if (dices[i].Equals(dices[i - 1]) && dices[i].Equals(dices[i - 2]))
                    {
                        return new CheckOutput(true, dices[i] * 3);
                    }
                }
            }

            if (pairs == 4)
            {
                for (int i = 3; i < dices.Count; i++)
                {
                    if (dices[i].Equals(dices[i - 1]) && dices[i].Equals(dices[i - 2]) && dices[i].Equals(dices[i - 3]))
                    {
                        return new CheckOutput(true, dices[i] * 4);
                    }
                }
            }

            return new CheckOutput(false, 0);
        }

        public CheckOutput StraightChecker(List<int> dices, string type)
        {
            bool success = false;
            dices = RemoveDuplicats(dices);
            dices.Sort();

            int requiredLength = type.ToLower() == "small" ? 4 : 5;
            
            if (dices.Count >= requiredLength)
            {
                success = true;
                for (int i = 1; i < requiredLength; i++)
                {
                    if (dices[i] != dices[i - 1] + 1)
                    {
                        success = false;
                        break;
                    }
                }
            }

            int result = 0;
            
            if (success)
            {
                if (type.ToLower() == "small")
                {
                    result = 15;
                }
                else if (type.ToLower() == "large")
                {
                    result = 20;
                }
            }

            return new CheckOutput(success, result);
        }

        public CheckOutput FullHouse(List<int> dices)
        {
            var counts = new Dictionary<int, int>();
            foreach (var die in dices)
            {
                if (counts.ContainsKey(die))
                    counts[die]++;
                else
                    counts[die] = 1;
            }

            bool hasThreeOfAKind = false;
            bool hasPair = false;

            foreach (var count in counts.Values)
            {
                if (count == 3)
                    hasThreeOfAKind = true;
                else if (count == 2)
                    hasPair = true;
            }

            bool success = hasThreeOfAKind && hasPair && counts.Count == 2;
            int result = success ? dices.Sum() : 0;

            return new CheckOutput(success, result);
        }

        public CheckOutput Yatzy(List<int> dices)
        {
            bool success = dices.All(die => die == dices[0]);
            int result = success ? 50 : 0;

            return new CheckOutput(success, result);
        }

        public CheckOutput Chance(List<int> dices)
        {
            return new CheckOutput(true, dices.Sum());
        }
        
        public List<int> RemoveDuplicats(List<int> list)
        {
            int i = 0;
            List<int> distinctElements = new List<int>();
            while (i < list.Count)
            {
                if (!distinctElements.Contains(list[i]))
                    distinctElements.Add(list[i]);
                i++;
            }
            return distinctElements;
        }
    }
}