# frozen_string_literal: true

#
# Copyright (C) 2014 - 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/>.

require_relative "../common"
require_relative "page_objects/assignment_page"
require_relative "page_objects/assignment_create_edit_page"

describe "assignments" do
  include_context "in-process server selenium tests"

  before(:once) do
    @user = user_with_pseudonym({ active_user: true })
    @pseudonym = @user.pseudonym
    @course = course_with_teacher({ user: @user, active_course: true, active_enrollment: true }).course
  end

  before do
    create_session(@pseudonym)
  end

  context "with points" do
    before do
      @assignment = @course.assignments.create!(
        name: "first test assignment",
        assignment_group: @course.assignment_groups.create!(name: "default")
      )
    end

    it "validates points for percentage grading (!= '')", priority: "2" do
      error_message = "Points value must be 0 or greater"
      points_validation(@assignment, error_message) do
        AssignmentCreateEditPage.select_grading_type "Percentage"
        AssignmentCreateEditPage.enter_points_possible ""
      end
    end

    it "validates points for percentage grading (digits only)", priority: "2" do
      error_message = "Points value must be a number"
      points_validation(@assignment, error_message) do
        AssignmentCreateEditPage.select_grading_type "Percentage"
        AssignmentCreateEditPage.enter_points_possible "taco"
      end
    end

    it "validates points for letter grading (!= '')", priority: "2" do
      error_message = "Points value must be 0 or greater"
      points_validation(@assignment, error_message) do
        AssignmentCreateEditPage.select_grading_type "Letter Grade"
        AssignmentCreateEditPage.enter_points_possible ""
      end
    end

    it "validates points for letter grading (digits only)", priority: "2" do
      error_message = "Points value must be a number"
      points_validation(@assignment, error_message) do
        AssignmentCreateEditPage.select_grading_type "Letter Grade"
        AssignmentCreateEditPage.enter_points_possible "taco"
      end
    end
  end

  context "with assignment creation" do
    before do
      @assignment_title = "grading options assignment"
      AssignmentCreateEditPage.visit_new_assignment_create_page @course.id
      AssignmentCreateEditPage.edit_assignment_name @assignment_title
    end

    %w[points percent pass_fail letter_grade gpa_scale].each do |grading_option|
      it "can create an assignment with #{grading_option} grading option", priority: "2" do
        AssignmentCreateEditPage.select_grading_type grading_option, :value
        AssignmentCreateEditPage.enter_points_possible "5"
        AssignmentCreateEditPage.select_submission_type "No Submission"
        AssignmentCreateEditPage.save_assignment
        expect(AssignmentPage.title).to include_text @assignment_title
        expect(Assignment.find_by(title: @assignment_title).grading_type).to eq grading_option
      end
    end
  end

  context "with GPA Scale Assignments" do
    before :once do
      # The 'GPA Scale' option is only available in the UI if the assignment is already of type
      # 'gpa_scale'. Therefore, we create the assignment here with type 'gpa_scale' so that the
      # 'GPA Scale' option is available when we go to edit the assignment
      @assignment = @course.assignments.create!(
        assignment_group: @course.assignment_groups.create!(name: "default"),
        grading_type: "gpa_scale",
        name: "first test assignment"
      )
    end

    it "validates points for GPA scale grading (!= '')", priority: "2" do
      error_message = "Points value must be 0 or greater"
      points_validation(@assignment, error_message) do
        AssignmentCreateEditPage.select_grading_type "GPA Scale"
        AssignmentCreateEditPage.enter_points_possible ""
      end
    end

    it "validates points for GPA scale grading (digits only)", priority: "2" do
      error_message = "Points value must be a number"
      points_validation(@assignment, error_message) do
        AssignmentCreateEditPage.select_grading_type "GPA Scale"
        AssignmentCreateEditPage.enter_points_possible "taco"
      end
    end

    it "shows 'GPA Scale' option if the assignment's type is GPA Scale", priority: "1" do
      AssignmentCreateEditPage.visit_assignment_edit_page @course.id, @assignment.id

      expect(f("#assignment_grading_type")).to contain_css('option[value="gpa_scale"]')
    end

    it "shows 'GPA Scale' option if the assignment's type is not GPA Scale", priority: "2" do
      @assignment.update!(grading_type: "points")
      AssignmentCreateEditPage.visit_assignment_edit_page @course.id, @assignment.id

      expect(f("#assignment_grading_type")).to contain_css('option[value="gpa_scale"]')
    end
  end

  def points_validation(assignment, error_message)
    AssignmentCreateEditPage.visit_assignment_edit_page @course.id, assignment.id
    yield if block_given?
    AssignmentCreateEditPage.assignment_save_button.click
    wait_for_ajaximations
    expect(f("#points_possible_errors")).to include_text(error_message)
  end
end
