class GameController < ApplicationController
  include QuizHelperMethods
  skip_before_action :require_player!, only: [ :index, :start ]

  before_action :set_node, only: [ :stage, :answer, :stage_result ]

  helper_method :root_node,
                :stage_index,
                :n_stages,
                :last_save_node

  def index
    @node = root_node
    not_found and return unless @node

    render action: @node.template
  end

  # POST
  def start
    player = Player.create(locale: I18n.locale.to_s)
    session[:player_id] = player.id
    redirect_to action: "facts"
  end


  def facts
    @node = root_node&.children&.facts&.first
  end


  def intro
    @node = root_node&.children&.intro&.first
  end


  def stage
  end


  # POST
  def answer
    @answer = @node.children.find_by(id: params[:value])
    @answer = @answer.children.sample if @answer&.chance?

    current_player.record_answer(stage_index, @answer.id)
    apply_score(score_entry_for(stage_index, @answer))

    bad_chance_outcome = @answer.parent&.chance? && @answer.bad_answer?

    if stage_index >= n_stages && !bad_chance_outcome
      redirect_to action: :done
    else
      redirect_to action: :stage_result, id: params[:id]
    end
  end



  def stage_result
    @result_node = @node.descendants.find_by(id: current_player.answer_id_for(stage_index))
    not_found and return unless @result_node
  end


  def last_save
    @node = last_save_node
  end


  # POST
  def answer_last_save
    @node = last_save_node
    not_found and return unless @node

    @answer = @node.children.find_by(id: params[:value])
    current_player.record_last_save_answer(@answer.id)
    apply_score(last_save_score_entry_for(@answer))

    redirect_to action: :done
  end


  def done
    current_player.update(is_done: true) unless current_player.is_done?

    if current_player.last_save_answer_id
      @node = last_save_node
      @result_node = @node.descendants.find_by(id: current_player.last_save_answer_id)
    else
      @node = stages.last
      @result_node = @node.descendants.find_by(id: current_player.answer_id_for(stages.size))
    end
  end


  def results
    @node = root_node.children.results.first
  end


private

  def root_node
    @root_node ||= Node.roots.viewable.first
  end


  def last_save_node
    @last_save_node ||= root_node.children.last_save.first
  end


  def stages
    @stages ||= root_node.children.ordered.stage
  end


  def set_node
    @node = stages[params[:id].to_i - 1]
    not_found and return unless @node
  end



  def stage_index
    @stage_index ||= stages.index(@node) + 1
  end


  def n_stages
    @n_stages ||= stages.size
  end



  def url_from_param
    return "" unless params[:url]

    # return File.join('', params[:url]) if I18n.default_locale == I18n.locale
    File.join("", I18n.locale.to_s, params[:url])
  end


  def question_scores
    @@question_scores ||= JSON.parse(Rails.root.join("config", "question_scores.json").read)
  end


  def score_entry_for(stage_idx, answer_node)
    stage_data = question_scores["stages"][stage_idx - 1]
    return nil unless stage_data

    if answer_node.parent&.chance?
      chance_entry = stage_data["answers"][answer_node.parent.position - 1]
      chance_entry&.dig("outcomes", answer_node.position - 1)
    else
      stage_data["answers"][answer_node.position - 1]
    end
  end


  def last_save_score_entry_for(answer_node)
    question_scores.dig("last_save", "answers", answer_node.position - 1)
  end


  def apply_score(entry)
    return unless entry

    current_player.add_to_score(
      overall: entry["overall"].to_i,
      impact: entry["impact"] || {}
    )
  end
end
