# frozen_string_literal: true

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

describe GradebookUploadsController do
  def course_with_graded_student
    @group = @course.assignment_groups.create!(name: "Some Assignment Group", group_weight: 100)
    @assignment = @course.assignments.create!(title: "Some Assignment", points_possible: 10, assignment_group: @group)
    @assignment.grade_student(@user, grade: "10", grader: @teacher)
    @assignment2 = @course.assignments.create!(title: "Some Assignment 2", points_possible: 10, assignment_group: @group)
    @assignment2.grade_student(@user, grade: "8", grader: @teacher)
    @course.recompute_student_scores
    @user.reload
    @course.reload
  end

  def generate_file(include_sis_id = false)
    file = Tempfile.new("csv.csv")
    file.puts(GradebookExporter.new(@course, @teacher, include_sis_id:).to_csv)
    file.close
    file
  end

  def upload_gradebook_import(course, file)
    data = Rack::Test::UploadedFile.new(file.path, "text/csv", true)
    post "create", params: { course_id: course.id, gradebook_upload: { uploaded_data: data } }
  end

  def check_create_response(include_sis_id = false)
    file = generate_file(include_sis_id)
    upload_gradebook_import(@course, file)
    expect(response).to be_successful
  end

  def setup_DA
    @course_section = @course.course_sections.create
    @student1, @student2, @student3 = create_users(3, return_type: :record)
    @assignment.only_visible_to_overrides = true
    @assignment.save
    @course.enroll_student(@student3, enrollment_state: "active")
    @section = @course.course_sections.create!(name: "test section")
    @section2 = @course.course_sections.create!(name: "second test section")
    student_in_section(@section, user: @student1)
    student_in_section(@section2, user: @student2)
    create_section_override_for_assignment(@assignment, { course_section: @section })
    @assignment2.only_visible_to_overrides = true
    @assignment2.save
    create_section_override_for_assignment(@assignment2, { course_section: @section2 })
    @course.reload
    @assignment.reload
    @assignment2.reload
  end

  before :once do
    course_with_teacher active_all: true
    student_in_course active_all: true
    course_with_graded_student
  end

  describe "POST 'create'" do
    it "requires authorization" do
      post "create", params: { course_id: @course.id }
      assert_unauthorized
    end

    context "with authorized teacher" do
      before { user_session(@teacher) }

      it "accepts a valid csv upload" do
        check_create_response
      end

      it "puts the uploaded data into a durable attachment so it's recoverable" do
        gradebook_import_file = generate_file
        upload_gradebook_import(@course, gradebook_import_file)
        attachment = Attachment.last
        expect(gradebook_import_file.path).to include(attachment.filename)
      end

      context "and final grade column" do
        before do
          @course.grading_standard_id = 0
          @course.save!
        end

        it "accepts a valid csv upload with a final grade column" do
          check_create_response
        end

        it "accepts a valid csv upload with sis id columns" do
          check_create_response(true)
        end
      end
    end
  end

  describe "GET 'data'" do
    it "requires authorization" do
      get "data", params: { course_id: @course.id }
      assert_unauthorized
    end

    it "retrieves an uploaded gradebook" do
      user_session(@teacher)
      progress = Progress.create!(tag: "test", context: @teacher)

      @gb_upload = GradebookUpload.new course: @course, user: @teacher, progress:, gradebook: { foo: "bar" }
      @gb_upload.save

      get "data", params: { course_id: @course.id }
      expect(response).to be_successful
      expect(response.body).to eq("{\"foo\":\"bar\"}")
    end

    it "destroys an uploaded gradebook after retrieval" do
      user_session(@teacher)
      progress = Progress.create!(tag: "test", context: @teacher)
      @gb_upload = GradebookUpload.new course: @course, user: @teacher, progress:, gradebook: { foo: "bar" }
      @gb_upload.save
      get "data", params: { course_id: @course.id }
      expect { GradebookUpload.find(@gb_upload.id) }.to raise_error(ActiveRecord::RecordNotFound)
      expect(response).to be_successful
    end
  end

  describe "GET 'show'" do
    it "requires authorization" do
      get "data", params: { course_id: @course.id }
      assert_unauthorized
    end

    it "sets js_env.bulk_update_override_scores_path" do
      user_session(@teacher)
      progress = Progress.create!(tag: "test", context: @teacher)

      @gb_upload = GradebookUpload.new course: @course, user: @teacher, progress:, gradebook: { foo: "bar" }
      @gb_upload.save

      get "show", params: { course_id: @course.id }
      expect(assigns[:js_env]).to have_key(:bulk_update_override_scores_path)
    end

    it "sets js_env.custom_grade_statuses to empty array if FF is off even if they exist" do
      Account.site_admin.disable_feature!(:custom_gradebook_statuses)
      CustomGradeStatus.create!(root_account: @course.root_account, name: "CARROT", color: "#000000", created_by: @teacher)
      user_session(@teacher)
      progress = Progress.create!(tag: "test", context: @teacher)

      @gb_upload = GradebookUpload.new course: @course, user: @teacher, progress:, gradebook: { foo: "bar" }
      @gb_upload.save

      get "show", params: { course_id: @course.id }
      expect(assigns[:js_env]).to have_key(:custom_grade_statuses)
      expect(assigns[:js_env][:custom_grade_statuses].length).to eq(0)
    end

    it "sets js_env.custom_grade_statuses if the FF is on" do
      Account.site_admin.enable_feature!(:custom_gradebook_statuses)
      CustomGradeStatus.create!(root_account: @course.root_account, name: "CARROT", color: "#000000", created_by: @teacher)
      user_session(@teacher)
      progress = Progress.create!(tag: "test", context: @teacher)

      @gb_upload = GradebookUpload.new course: @course, user: @teacher, progress:, gradebook: { foo: "bar" }
      @gb_upload.save

      get "show", params: { course_id: @course.id }
      expect(assigns[:js_env]).to have_key(:custom_grade_statuses)
      expect(assigns[:js_env][:custom_grade_statuses].length).to eq(1)
    end
  end
end
