# frozen_string_literal: true

#
# Copyright (C) 2012 - 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 "nokogiri"

describe Quizzes::QuizzesController do
  def create_section_override(section, due_at)
    override = assignment_override_model(quiz: @quiz)
    override.set = section
    override.override_due_at(due_at)
    override.save!
  end

  describe "#show" do
    before do
      course_with_teacher_logged_in(active_all: true)
      assignment_model(course: @course)
      quiz_model(course: @course, assignment_id: @assignment.id)
      @quiz.update_attribute :due_at, 5.days.from_now
      @cs1 = @course.default_section
      @cs2 = @course.course_sections.create!
    end

    it "renders page title as Quizzes: Course Name" do
      get "/courses/#{@course.id}/quizzes"

      expect(Nokogiri::HTML5(response.body).title).to eq("Quizzes: #{@course.name}")
    end

    context "with overridden due dates" do
      include TextHelper

      context "with no overrides" do
        it "shows a due date for 'Everyone'" do
          get "/courses/#{@course.id}/quizzes/#{@quiz.id}"

          doc = Nokogiri::HTML5(response.body)
          expect(doc.css(".assignment_dates").text).to include "Everyone"
          expect(doc.css(".assignment_dates").text).not_to include "Everyone else"
        end
      end

      context "with some sections overridden" do
        before do
          @due_at = 3.days.from_now
          create_section_override(@cs1, @due_at)
        end

        it "shows an overridden due date for student" do
          @course.enroll_user(user_factory, "StudentEnrollment", enrollment_state: "active")
          user_session(@user)

          get "/courses/#{@course.id}/quizzes/#{@quiz.id}"

          doc = Nokogiri::HTML5(response.body)
          expect(doc.css("#quiz_student_details .value").first.text).to include(datetime_string(@due_at))
        end

        it "shows 'Everyone else' when some sections have a due date override" do
          get "/courses/#{@course.id}/quizzes/#{@quiz.id}"

          doc = Nokogiri::HTML5(response.body)
          expect(doc.css(".assignment_dates").text).to include "Everyone else"
        end
      end

      context "with all sections overridden" do
        before do
          @due_at1, @due_at2 = 3.days.from_now, 4.days.from_now
          create_section_override(@cs1, @due_at1)
          create_section_override(@cs2, @due_at2)
        end

        it "shows multiple due dates to teachers" do
          get "/courses/#{@course.id}/quizzes/#{@quiz.id}"

          doc = Nokogiri::HTML5(response.body)
          expect(doc.css(".assignment_dates tbody tr").count).to be 2
          expect(doc.css(".assignment_dates tbody tr > td:first-child").text)
            .to include(datetime_string(@due_at1), datetime_string(@due_at2))
        end

        it "does not show a date for 'Everyone else'" do
          get "/courses/#{@course.id}/quizzes/#{@quiz.id}"

          doc = Nokogiri::HTML5(response.body)
          expect(doc.css(".assignment_dates").text).not_to include "Everyone"
        end
      end
    end

    context "SpeedGrader" do
      it "links to SpeedGrader when not large_roster" do
        @course.large_roster = false
        @course.save!
        get "/courses/#{@course.id}/quizzes/#{@quiz.id}"
        expect(response.body).to match(/SpeedGrader/)
      end

      it "does not link to SpeedGrader when large_roster" do
        @course.large_roster = true
        @course.save!
        get "/courses/#{@course.id}/quizzes/#{@quiz.id}"
        expect(response.body).not_to match(/SpeedGrader/)
      end

      it "does not link to SpeedGrader when moderated grader limit is reached" do
        allow_any_instance_of(Assignment).to receive(:can_view_speed_grader?).and_return(false)
        get "/courses/#{@course.id}/quizzes/#{@quiz.id}"
        expect(response.body).not_to match(/SpeedGrader/)
      end
    end
  end

  context "show_student" do
    before do
      course_with_student_logged_in(active_all: true)
      course_quiz true
      post "/courses/#{@course.id}/quizzes/#{@quiz.id}/take?user_id=#{@student.id}"

      get "/courses/#{@course.id}/quizzes/#{@quiz.id}/take"
    end

    context "Show Center resume button" do
      it "shows resume button in the center" do
        get "/courses/#{@course.id}/quizzes/#{@quiz.id}"

        doc = Nokogiri::HTML5(response.body)
        expect(doc.css("#not_right_side .take_quiz_button").text).to include "Resume Quiz"
      end
    end

    context "Not show right_side resume button" do
      it "does not show resume button on right_side" do
        get "/courses/#{@course.id}/quizzes/#{@quiz.id}"

        doc = Nokogiri::HTML5(response.body)
        expect(doc.css("#right-side").text).not_to include "Resume Quiz"
      end
    end
  end

  describe "#history" do
    context "pending_review" do
      def mkquiz
        quiz_with_graded_submission([{ question_data: { :name => "question 1", :points_possible => 1, "question_type" => "essay_question" } },
                                     { question_data: { :name => "question 2", :points_possible => 1, "question_type" => "essay_question" } }])
        course_with_teacher_logged_in(active_all: true, course: @course)
      end

      def mksurvey
        survey_with_submission([{ question_data: { :name => "question 1", :points_possible => 1, "question_type" => "essay_question" } },
                                { question_data: { :name => "question 2", :points_possible => 1, "question_type" => "essay_question" } }])
        course_with_teacher_logged_in(active_all: true, course: @course)
      end

      it "lists the questions needing review" do
        mkquiz
        get "/courses/#{@course.id}/quizzes/#{@quiz.id}/history?quiz_submission_id=#{@quiz_submission.id}"
        expect(response.body).to match(/The following questions need review/)
        expect(response.body).not_to match(/The quiz has changed significantly since this submission was made/)
        doc = Nokogiri::HTML5(response.body)
        needing_review = doc.at_css("#questions_needing_review")
        expect(needing_review).to be_present
        expect(needing_review.children.css("li a").map(&:text)).to eq(@quiz.quiz_data.pluck("name"))
      end

      it "displays message about the quiz changing significantly" do
        allow_any_instance_of(Quizzes::Quiz).to receive(:changed_significantly_since?).and_return(true)
        mkquiz
        @quiz.check_if_submissions_need_review
        @quiz_submission.submission_data.each { |q| q[:correct] = "false" }
        @quiz_submission.save
        get "/courses/#{@course.id}/quizzes/#{@quiz.id}/history?quiz_submission_id=#{@quiz_submission.id}"
        expect(response.body).not_to match(/The following questions need review/)
        expect(response.body).to match(/The quiz has changed significantly since this submission was made/)
      end

      it "displays both messages" do
        allow_any_instance_of(Quizzes::Quiz).to receive(:changed_significantly_since?).and_return(true)
        mkquiz
        get "/courses/#{@course.id}/quizzes/#{@quiz.id}/history?quiz_submission_id=#{@quiz_submission.id}"
        expect(response.body).to match(/The following questions need review/)
        expect(response.body).to match(/The quiz has changed significantly since this submission was made/)
        doc = Nokogiri::HTML5(response.body)
        needing_review = doc.at_css("#questions_needing_review")
        expect(needing_review).to be_present
        expect(needing_review.children.css("li a").map(&:text)).to eq(@quiz.quiz_data.pluck("name"))
      end

      it "shoudn't show the user's name/email when it's an anonymous submission" do
        mksurvey

        # add some crazy names and email address that are unlikely to be matched accidentally
        crazy_unlikely_to_be_matched_name = "1p3h5Yns[y>s^*:]zi^1|h,M"
        @student.name = crazy_unlikely_to_be_matched_name
        @student.sortable_name = crazy_unlikely_to_be_matched_name
        pseudonym @student, username: "1p3h5Ynsyszi1hM@1p3h5Ynsyszi1hM.com"
        @student.save!
        @student.reload
        get "/courses/#{@course.id}/quizzes/#{@quiz.id}/history?quiz_submission_id=#{@quiz_submission.id}"
        expect(response.body).not_to match @student.name
        expect(response.body).not_to match @student.sortable_name
        expect(response.body).not_to match @student.email
      end
    end
  end

  def course_quiz(active = false)
    @quiz = @course.quizzes.create
    @quiz.workflow_state = "available" if active
    @quiz.save!
    @quiz
  end
end
