module Typingtutor
  class Stats
    FILE = File.expand_path('~/.typingtutor')

    def initialize
      @stats = {}
      @stats.merge!(YAML.load(IO.read(FILE))) if File.exists?(FILE)
      @stats[:created_at] ||= Time.now
      @stats[:total] ||= {}
      @stats[:exercises]  ||= {}
      @stats[:words] ||= {}
      @stats[:letters] ||= {}
    end

    def save
      @stats[:updated_at] = Time.now
      IO.write(FILE, YAML.dump(@stats))
    end

    def record_exercise(exercise)
      @stats[:exercises][exercise.name] ||= {}
      @stats[:exercises][exercise.name][:runs] ||= 0
      @stats[:exercises][exercise.name][:runs] += 1
      @stats[:exercises][exercise.name][:last_run] = Time.now
      @stats[:exercises][exercise.name][:last_run_results] = exercise.results

      # update totals
      @stats[:total][:runs] ||= 0
      @stats[:total][:runs] += 1

      [:time, :chars, :correct_chars, :words, :keystrokes].each do |metric|
        @stats[:total][metric] ||= 0
        @stats[:total][metric] += exercise.results[metric]
      end

      @stats[:total][:max_wpm] ||= 0
      @stats[:total][:max_wpm] = [@stats[:total][:max_wpm], exercise.results[:gross_wpm]].max
      @stats[:total][:avg_wpm] = @stats[:total][:words] / (@stats[:total][:time] / 60)
    end

    def record_word(word)
      # TODO
    end

    def record_letter(letter, ok)
      return if letter == ' '
      @stats[:letters][letter] ||= {}
      @stats[:letters][letter][:total] ||= {}
      @stats[:letters][letter][:total][:count] ||= 0
      @stats[:letters][letter][:total][:count] += 1
      @stats[:letters][letter][:total][:correct] ||= 0
      @stats[:letters][letter][:total][:correct] += 1 if ok
      @stats[:letters][letter][:total][:accuracy] = (@stats[:letters][letter][:total][:correct].to_f / @stats[:letters][letter][:total][:count].to_f * 100).round
    end

    def print
      puts "------------------------"
      puts "Your avg speed: #{@stats[:total][:avg_wpm].round} wpm"
      puts "Your max speed: #{@stats[:total][:max_wpm].round} wpm"
    end

    def print_full
      puts "Accuracy per letter:"
      worst_letters.each {|letter, accuracy| puts "#{letter}: #{accuracy.round}%"}

      if @stats[:exercises].size > 0
        puts
        puts "Exercises:"
        @stats[:exercises].each do |name, data|
          puts "- #{name}: #{data[:runs]} runs, #{data[:last_run_results][:gross_wpm].round} wpm"
        end
      end
      puts
      puts "Exercises played: #{@stats[:total][:runs] || 0}"
      puts "Time played: #{(@stats[:total][:time] || 0).round.divmod(60).join('m ')}s"
      puts "Avg speed: #{(@stats[:total][:avg_wpm] || 0).round} wpm"
      puts "Max speed: #{(@stats[:total][:max_wpm] || 0).round} wpm"
    end

    def worst_letters
      accuracy = @stats[:letters].map {|letter, data| [letter, data[:total][:accuracy]]}.to_h # { "a" => 100, "b" => 98 }
      accuracy.reject! {|key, value| value == 100}
      accuracy.reject! {|key, value| key !~ /\w/ }
      accuracy = accuracy.sort_by {|key, value| value }.to_h
      accuracy
    end
  end
end
