using System;
using System.Collections.Generic;
using System.Linq;

namespace Core
{
    public class LetterPositionFrequency : IComparer<string>
    {
        private readonly Dictionary<char, int>[] _letterFrequencies;

        private LetterPositionFrequency(Dictionary<char, int>[] letterFrequencies)
        {
            _letterFrequencies = letterFrequencies;
        }


        public LetterPositionFrequency(DictionarySearcher dictionarySearcher, int wordLen)
            : this(GetLetterPositionFreq(dictionarySearcher.GetWords(), wordLen))
        {

        }


        public LetterPositionFrequency(WordleUtil wordleUtil, int wordLen)
            : this(GetLetterPositionFreq(wordleUtil.Words, wordLen))
        {
        }

        public LetterPositionFrequency(IList<string> words, int wordLen)
            : this(GetLetterPositionFreq(words, wordLen))
        {
        }

        public static Dictionary<char, int>[] GetLetterPositionFreq(IList<string> words, int wordLen)
        {
            var ws = words.Where(w => w.Length == wordLen).ToList();

            var freqList = new Dictionary<char, int>[wordLen];
            for (var i = 0; i < wordLen; i++)
            {
                var letters = Enumerable.Range(0, 26).Select(r => Convert.ToChar('A' + r));
                freqList[i] =
                    letters.ToDictionary(c => c,
                        c => ws.Count(w => w[i] == c)
                    );
            }

            return freqList;
        }

        public IEnumerable<Tuple<string, int>> ScoreWords(IEnumerable<string> words, WordleUtil wordleUtil = null)
        {
            return 
                from word in words 
                let score = 
                    word.Select((c, i) => _letterFrequencies[i][c]).Sum()
                select
                    wordleUtil != null 
                    ? Tuple.Create(word, Convert.ToInt32(wordleUtil.FactorRepeatedLetters(word, score)))
                    : Tuple.Create(word, score)
                ;
        }

        public List<string> SortWords(IEnumerable<string> words, WordleUtil wordleUtil = null)
        {
            return ScoreWords(words, wordleUtil)
                .OrderByDescending(w => w.Item2)
                .Select(w => w.Item1)
                .ToList();
        }

        private int ScoreWord(string word)
        {
            return word.Select((c, i) => _letterFrequencies[i][c]).Sum();
        }

        public int Compare(string x, string y)
        {
            return ScoreWord(y).CompareTo(ScoreWord(x));
        }

    }
}
