# frozen_string_literal: true

#
# Copyright (C) 2018 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#

RSpec.shared_examples "a provisional grades status action" do |controller|
  describe "status" do
    before(:once) do
      course_with_teacher(active_all: true)
      ta_in_course(active_all: true)
      @student = student_in_course(active_all: true).user
      @assignment = @course.assignments.create!(moderated_grading: true, grader_count: 2)
      @submission = @assignment.submit_homework @student, body: "EHLO"
      @path = "/api/v1/courses/#{@course.id}/assignments/#{@assignment.id}/#{controller}/status"
      @resource_pair = if controller == :anonymous_provisional_grades
                         { anonymous_id: @submission.anonymous_id }
                       else
                         { student_id: @submission.user_id }
                       end
      @params = {
        controller:,
        action: :status,
        format: :json,
        course_id: @course.to_param,
        assignment_id: @assignment.to_param
      }.merge(@resource_pair)
    end

    it "gives a status message of unauthorized when called as a student" do
      json = api_call_as_user(@student, :get, @path, @params, {}, {}, { expected_status: 403 })
      expect(json["status"]).to eq "unauthorized"
    end

    it "gives an error message of not authorized when called as a student" do
      json = api_call_as_user(@student, :get, @path, @params, {}, {}, { expected_status: 403 })
      expect(json.fetch("errors")).to include({ "message" => "user not authorized to perform that action" })
    end

    it "when called as a student, error message is not found" do
      @params[@resource_pair.flatten.first] = nil
      json = api_call_as_user(@ta, :get, @path, @params, {}, {}, { expected_status: 404 })
      expect(json.fetch("errors")).to include({ "message" => "The specified resource does not exist." })
    end

    it "is authorized when the user is an admin with permission to select final grade" do
      admin = account_admin_user(account: @course.account)
      api_call_as_user(admin, :get, @path, @params.merge(last_updated_at: 1.day.ago(@submission.updated_at)), {}, {})
      expect(response).to be_successful
    end

    it "is forbidden when the user is an admin without permission to select final grade" do
      admin = account_admin_user(account: @course.account)
      @course.account.role_overrides.create!(role: admin_role, enabled: false, permission: :select_final_grade)
      api_call_as_user(admin, :get, @path, @params.merge(last_updated_at: 1.day.ago(@submission.updated_at)), {}, {})
      expect(response).to be_forbidden
    end

    context "when called as a moderator" do
      let(:provisional_grades_json) do
        json = api_call_as_user(@teacher, :get, @path, @params, {}, {}, { expected_status: 200 })
        json.fetch("provisional_grades")
      end

      before(:once) do
        @assignment.update!(grader_count: 1, final_grader: @teacher)

        @ta.update!(name: "Nobody Important")
        @submission.find_or_create_provisional_grade!(@ta)
        @params.merge!(last_updated_at: @submission.updated_at - 1)
      end

      it "omits the scorer_name parameter from provisional grades if the final grader cannot view grader names" do
        @assignment.update!(grader_names_visible_to_final_grader: false)
        expect(provisional_grades_json.first).not_to have_key("scorer_name")
      end

      it "includes the scorer_name parameter for provisional grades if the final grader can view grader names" do
        @assignment.update!(grader_names_visible_to_final_grader: true)
        expect(provisional_grades_json.first["scorer_name"]).to eq "Nobody Important"
      end

      it "returns results for deactivated students" do
        @course.enrollments.find_by(user: @student).deactivate
        expect(provisional_grades_json.first["scorer_name"]).to eq "Nobody Important"
      end

      it "returns results for concluded students" do
        @course.enrollments.find_by(user: @student).conclude
        expect(provisional_grades_json.first["scorer_name"]).to eq "Nobody Important"
      end
    end
  end
end
