# The game class
class Game < ActiveRecord::Base
  belongs_to :table
  has_many :seats
  has_many :players, dependent: :destroy
  has_many :users, through: :players
  has_many :player_cards, through: :players
  has_many :plays, through: :players
  belongs_to :play_to_beat
  accepts_nested_attributes_for :players
  #validates :title, presence: true
  after_create :add_table

  # Returns the newest joinable game or creates a new game if none are found
  scope :play_now, lambda { |user|
    where(status:nil).joins("LEFT OUTER JOIN players ON players.game_id = games.id").group("games.id").having("count(players) < 4").last || Game.create(title: "Game " + user.soft_token[0..4])
  }

  def start
    validate_startable
    return false unless startable?

    # Start the game
    self.status = 'Game Started'

    # Create a deck
    d = Deck.new
    # Shuffle the deck
    d.cards.shuffle!
    # Deal the cards
    players.each do |player|
      13.times do
        card = d.cards.shift
        player.player_cards.new(card.instance_values)
      end
      player.save
    end

    # Set status to first turn
    # Player with the lowest card
    self.status = 'First Play at: ' + self.lowest_card.player.display_name
    self.controlling_player_id = self.lowest_card.player.id
    save
  end

  def winner
    self.players.find_by_id(self.winner_player_id)
  end

  def validate_startable
    @player_count = players.count
    @user_count = players.where.not(soft_token: nil).count
    errors[:players] = 'Must be at least 2 players.'  if @user_count < 2
    errors[:players] = 'Must be less than 5 players.'  if @user_count > 4
    errors[:status]  = 'Game already started...' if self.status.nil? == false
    errors[:player_cards]  = 'Cards already dealt...' unless player_cards.empty?
    fail StandardError, errors if errors.count > 0
    return true
  end

  def current_hand
    return nil
  end

  def startable?
    begin
      self.validate_startable
    rescue
      return false
    end
  end

  def lowest_card
    self.player_cards.order(:value).first
  end

  def add_player_from_user(user)
    return false unless self.joinable?(user)
    new_player = self.players.create(user: user, soft_token: user.soft_token)
  end

  def remove_player_from_user(user)
    return false unless self.has_user? user

    if self.players.exists?(user_id: user.id)
      @player = self.players.find_by(user_id: user.id)
    elsif self.players.exists?(soft_token: user.soft_token)
      @player = self.players.find_by(soft_token: user.soft_token)
    end

    if @player
      @player.user_id = nil
      @player.soft_token = nil
    end

  end

  def can_accomodate(user)
    !(already_has?(user) || full?)
  end

  #TODO: Which has_user? method is better? Probably has_user?.
  def already_has?(user)
    self.players.pluck(:user_id, :soft_token).flatten.compact.to_set.intersect? ([user.id, user.soft_token].to_set)
  end

  def has_user? user
    if user.id
      return true if self.players.exists?(user_id: user.id)
    end
    if user.soft_token
      return true if self.players.exists?(soft_token: user.soft_token)
    end
    return false
  end


  def full?
    players.count >= 4
  end

  def set_controlling_player(arg)
    case arg
    when 'next'
      self.controlling_player_id = self.next_player_id
    end

    # Clear play to beat if play returns to owner
    # if self.play_to_beat.try(:player).try(:id) == self.controlling_player_id
    #   self.play_to_beat_id = nil
    # end
  end

  def joinable? user
    !self.has_user?(user) && !self.full?
  end

  def player_ids_by_seat_order
    player_ids = self.seats.order(:position).select {|s| ( s.player.present? && s.player.inventory.count > 0) ? s.player_id : nil}.compact.map {|s| s.player_id}
  end

  def next_player_id
    @controlling_player_index = self.player_ids_by_seat_order.index(controlling_player_id)
    # TODO Fix bug 
    @controlling_player_index ||= 0
    player_ids_by_seat_order[(@controlling_player_index + 1) % self.player_ids_by_seat_order.length]
  end

  # The player whose turn it is
  def controlling_player
    if self.controlling_player_id
      self.players.find_by_id(self.controlling_player_id)
    end
  end

  # The user whose turn it is
  def controlling_user
    self.players.find(self.controlling_player_id).user
  end

  def hand_to_beat
    self.play_to_beat.try(:play).try(:hand)
  end

  def player_to_beat
    self.play_to_beat.try(:play).try(:player)
  end

  def started?
    !self.status.nil?
  end

  def over?
    return false unless self.started?
    @inventory_counts = self.players.map {|p| p.player_cards.count > 0 ? p.inventory.count : nil}
    @inventory_counts.include? 0
  end

private

  def add_table
    self.table ||= Table.create current_game_id: self.id
    self.seats = self.table.seats
    self.seats.each do |seat|
      if (seat.user_id || seat.user_soft_token)
        new_player = self.players.create(user_id: seat.user_id, soft_token: seat.user_soft_token)
        seat.player = new_player
        seat.save
      end
    end
    self.save
  end

end
