require 'game_of_thrones_api/version'
require 'httparty'

# There are 3 'get' methods, each method returns an Array of all the records
# for that specific category.
#
# Currently there are 12 Books, 2134 Characters and 444 Family Houses.
#
# Each 'get' method is memoized for performance and to reduce API calls.
#
# Each 'find' method takes a 'term' and searches the name column of that
# category for any matches.

module GameOfThronesApi
  include HTTParty
  format :json

  BASE_ENDPOINT  = "http://anapioficeandfire.com/api".freeze

  WORD_PARTICLES = %w(and or the over to the a but of for with).freeze

  def self.get_books
    @get_books ||= begin
      response    = get("#{BASE_ENDPOINT}/books?page=1&pageSize=50")
      total_pages = get_page_count(response)

      get_all_records('books', response, total_pages)
    end
  end

  def self.find_book(name)
    books ||= GameOfThronesApi.get_books
    query   = titleize_query(name)

    books.select { |book| book['name'].include?(query) }
  end

  def self.get_characters
    @get_characters ||= begin
      response    = get("#{BASE_ENDPOINT}/characters?page=1&pageSize=50")
      total_pages = get_page_count(response)

      get_all_records('characters', response, total_pages)
    end
  end

  def self.find_character(name)
    characters ||= GameOfThronesApi.get_characters
    query        = titleize_query(name)

    characters.select { |character| character['name'].include?(query) }
  end

  def self.get_houses
    @get_houses ||= begin
      response    = get("#{BASE_ENDPOINT}/houses?page=1&pageSize=50")
      total_pages = get_page_count(response)

      get_all_records('houses', response, total_pages)
    end
  end

  def self.find_house(name)
    houses ||= GameOfThronesApi.get_houses
    query    = titleize_query(name)

    houses.select { |house| house['name'].include?(query) }
  end

  module_function

  def name_query(filter)
    "/?name=#{uri_escape(filter)}"
  end

  def uri_escape(term)
    term.gsub(' ', '%20')
  end

  # The pagination information is in the Headers
  # We retrieve the links from the Headers using a regex
  # There will always be 3 links, the last link, redirects to the last page.
  # We take the page number from the last link as our page count.
  def get_page_count(response)
    page_links = response.headers['link'].scan(/<(\S+)>/).flatten
    /\?page\=(\d+)\&/.match(page_links.last)[1].to_i
  end

  def titleize_query(query)
    split_words =
      query.split.map.with_index do |word, index|
        if WORD_PARTICLES.exclude?(word) || index.zero?
          word.capitalize
        else
          word
        end
      end

    split_words.join(' ')
  end

  # The API results are paginated, just looping through the pages to collect
  # all the records associated with the category.
  def get_all_records(category, response, total_pages, page = 1)
    characters  = response.parsed_response

    while total_pages >= page
      page       += 1
      characters += get("#{BASE_ENDPOINT}/#{category}?page=#{page}&pageSize=50").parsed_response
    end

    characters
  end
end