require 'test_helper'

class AnswerLockingTest < ActionDispatch::IntegrationTest
  include Devise::Test::IntegrationHelpers

  setup do
    scaffold_template
    scaffold_plan
    @question = Question.create(text: 'Test question', section: @plan.template.phases.first.sections.first,
                                question_format: QuestionFormat.where(option_based: false).first, number: 99)

    @owner = @plan.owner
    users = User.all
    @collaborator = users[users.find_index{ |u| u != @owner }]

    # Make the 2nd user an editor of the plan
    Role.create!(user_id: @collaborator.id, plan_id: @plan.id, access: 4)
    @plan.reload
  end

  test 'answer#create_or_update responds not_found when a plan does not exist' do
    userA = Answer.create!(user: @owner, question: @question,
                           text: "Initial answer - by UserA").attributes
    sign_in @owner
    params = obj_to_params(userA)
    params[:answer][:plan_id] = 'foo'
    post create_or_update_answers_path(params)
    assert_response :not_found
    assert_equal(_('There is no plan with id %{id} for which to create or update an answer') %{ :id => 'foo' }, ActiveSupport::JSON.decode(@response.body)['msg'])
  end

  test 'answer#create_or_update responds not found when a question does not exist for a plan' do
    userA = Answer.create!(user: @owner, plan: @plan,
                           text: "Initial answer - by UserA").attributes
    sign_in @owner
    params = obj_to_params(userA)
    params[:answer][:question_id] = 'foo'
    post create_or_update_answers_path(params)
    assert_response :not_found
    assert_equal(
      _("There is no question with id %{question_id} associated to plan id %{plan_id} "\
        "for which to create or update an answer") %{ :question_id => 'foo', :plan_id => @plan.id }, ActiveSupport::JSON.decode(@response.body)['msg'])
  end

  # ----------------------------------------------------------
  test 'user receives a lock notification if the answer was UPDATED while they were working' do
    userA = Answer.create!(user: @owner, plan: @plan, question: @question,
                           text: "Initial answer - by UserA").attributes
    userB = userA.clone

    # Signin as UserA and insert the new answer
    sign_in @plan.owner
    userA['text'] += " - Updated by userA"

    post create_or_update_answers_path(obj_to_params(userA))
    assert_response :success
    assert_equal "application/json", @response.content_type
    updated = Answer.find_by(plan: @plan, question: @question)
    assert_equal "Initial answer - by UserA - Updated by userA", updated.text
    assert_equal @plan.owner.id, updated.user_id

    # Make sure the answers/locking partial is NOT displayed
    assert_not @response.body.include?(_('The following answer cannot be saved')), "expected there to be no lock error messaging"
    assert @response.body.include?(_('Answered'))
    assert @response.body.include?("#{_(' by')} #{@plan.owner.name}"), "expected the messaging to say the plan was updated by the plan owner"

    # Signin as UserB and try to insert the new answer but fail
    sign_in @collaborator
    userB['text'] += " - Updated by userB"

    post create_or_update_answers_path(obj_to_params(userB))
    assert_response :success
    assert_equal "application/json", @response.content_type
    updated = Answer.find_by(plan: @plan, question: @question)
    assert_equal "Initial answer - by UserA - Updated by userA", updated.text
    assert_equal @plan.owner.id, updated.user_id

    # Make sure the answer-notice IS displayed
    assert @response.body.include?(_('The following answer cannot be saved')), "expected there to be lock error messaging"
    assert @response.body.include?(_('since %{name} saved the answer below while you were editing. Please, combine your changes and then save the answer again.') % { name: @plan.owner.name}), "expected the messaging to STILL say the plan was updated by the plan owner"
    assert @response.body.include?(_('Answered')), "expected the messaging to include the status"
  end

# ----------------------------------------------------------
  private
    def obj_to_params(attributes)
      {
       answer: {
        plan_id: attributes['plan_id'],
        question_id: attributes['question_id'],
        text: attributes['text'],
        lock_version: attributes['lock_version']}
      }
    end
end
