# 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/>.

require File.expand_path(File.dirname(__FILE__) + '/../../../../spec/spec_helper')
require 'zip/filesystem'

if Qti.migration_executable

describe Qti::Converter do
  before do
    course_with_teacher(:active_all => true)
  end

  it "should import duplicate files once, without munging" do
    setup_migration
    do_migration

    expect(@course.attachments.count).to eq 2
    expect(@course.attachments.map(&:filename).sort).to eq ['header-logo.png', 'smiley.jpg']
    attachment = @course.attachments.detect { |a| a.filename == 'header-logo.png' }
    quiz = @course.quizzes.last
    expect(quiz).to be_present
    expect(quiz.quiz_questions.count).to eq 2
    quiz.quiz_questions.each do |q|
      text = Nokogiri::HTML::DocumentFragment.parse(q.question_data['question_text'])
      expect(text.css('img').first['src']).to eq "/courses/#{@course.id}/files/#{attachment.id}/preview"

      # verify that the associated assessment_question got links translated
      aq = q.assessment_question
      text = Nokogiri::HTML::DocumentFragment.parse(aq.question_data['question_text'])
      expect(text.css('img').first['src']).to match %r{/assessment_questions/#{aq.id}/files/\d+/download\?verifier=\w+}

      if aq.question_data['answers'][1]["comments_html"] =~ /\<img/
        text = Nokogiri::HTML::DocumentFragment.parse(aq.question_data['answers'][1]["comments_html"])
        expect(text.css('img').first['src']).to match %r{/assessment_questions/#{aq.id}/files/\d+/download\?verifier=\w+}
      end
    end
    expect(quiz.assignment).to_not be_nil
  end

  it "should bring in canvas meta data" do
    setup_migration(File.expand_path("../fixtures/qti/canvas_qti.zip", __FILE__))
    do_migration
    expect(@course.quizzes.count).to eq 1
    expect(@course.quizzes.first.description).to eq "<p>Quiz Description</p>"
  end

  describe "applying respondus settings" do
    before do
      @copy = Tempfile.new(['spec-canvas', '.zip'])
      FileUtils.cp(fname, @copy.path)
      Zip::File.open(@copy.path) do |zf|
        zf.file.open("settings.xml", +'w') do |f|
          f.write <<-XML
          <settings>
            <setting name='hasSettings'>true</setting>
            <setting name='publishNow'>true</setting>
          </settings>
          XML
        end
      end
      setup_migration(@copy.path)
      @migration.update_migration_settings(:apply_respondus_settings_file => true)
      @migration.save!
    end

    it "should publish as assignment on import if specified" do
      do_migration

      quiz = @course.quizzes.last
      expect(quiz).to be_present
      expect(quiz.assignment).not_to be_nil
      expect(quiz.assignment.title).to eq quiz.title
      expect(quiz.assignment).to be_published
    end

    it "should re-use the same assignment on update" do
      do_migration

      setup_migration(@copy.path)
      @migration.update_migration_settings(:apply_respondus_settings_file => true, :quiz_id_to_update => @course.quizzes.last.id)
      @migration.save!
      do_migration

      expect(@course.quizzes.size).to eq 1
      expect(@course.assignments.size).to eq 1
      quiz = @course.quizzes.last
      expect(quiz).to be_present
      expect(quiz.assignment).not_to be_nil
      expect(quiz.assignment.title).to eq quiz.title
      expect(quiz.assignment).to be_published
    end

    it "should correctly set the assignment submission_type" do
      do_migration
      assign = @course.assignments.last
      expect(assign.submission_types).to eq 'online_quiz'
      expect(assign.quiz.for_assignment?).to be_truthy
    end
  end

  it "should publish spec-canvas-1 correctly" do
    setup_migration
    do_migration

    quiz = @course.quizzes.last
    expect(quiz).to be_present
    expect(quiz.quiz_questions.size).to eq 2
    # various checks on the data
    qq = quiz.quiz_questions.first
    d = qq.question_data
    expect(d['correct_comments']).to eq "I can't believe you got that right. Awesome!"
    expect(d['correct_comments_html']).to eq "I can't <i>believe </i>you got that right. <b>Awesome!</b>"
    expect(d['incorrect_comments_html']).to eq "<b>Wrong. </b>That's a bummer."
    expect(d['points_possible']).to eq 3
    expect(d['question_name']).to eq 'q1'
    expect(d['answers'].map { |a| a['weight'] }).to eq [0,100,0]
    expect(d['answers'].map { |a| a['comments'] }).to eq ['nope', 'yes!', nil]
    attachment = @course.attachments.detect { |a| a.filename == 'smiley.jpg' }
    expect(d['answers'].map { |a| a['comments_html'] }).to eq [nil, %{yes! <img src="/courses/#{@course.id}/files/#{attachment.id}/preview" alt="">}, nil]
  end

  it "should import respondus question types" do
    setup_migration(File.expand_path("../fixtures/canvas_respondus_question_types.zip", __FILE__))
    do_migration

    quiz = @course.quizzes.last
    expect(quiz).to be_present
    expect(quiz).not_to be_available
    expect(quiz.quiz_questions.size).to eq 9

    match_ignoring(quiz.quiz_questions.map(&:question_data), RESPONDUS_QUESTIONS, %w[id assessment_question_id match_id prepped_for_import is_quiz_question_bank question_bank_migration_id quiz_question_id])
  end

  it "should apply respondus settings" do
    setup_migration(File.expand_path("../fixtures/canvas_respondus_question_types.zip", __FILE__))
    @migration.update_migration_settings(:apply_respondus_settings_file => true)
    @migration.save!
    do_migration

    quiz = @course.quizzes.last
    expect(quiz).to be_present
    expect(quiz).to be_available
  end

  it "should be able to import directly into an assessment question bank" do
    setup_migration(File.expand_path("../fixtures/canvas_respondus_question_types.zip", __FILE__))
    @migration.update_migration_settings(:migration_ids_to_import =>
                                             { :copy => { :all_quizzes => false, :all_assessment_question_banks => true} })
    @migration.save!
    do_migration

    expect(@course.quizzes.count).to eq 0
    qb = @course.assessment_question_banks.last
    expect(qb).to be_present
    expect(qb.assessment_questions.size).to eq 9
    data = qb.assessment_questions.map(&:question_data).sort_by!{|q| q["migration_id"]}
    match_ignoring(data, RESPONDUS_QUESTIONS, %w[id assessment_question_id match_id missing_links position prepped_for_import is_quiz_question_bank question_bank_migration_id quiz_question_id])
  end

  def match_ignoring(a, b, ignoring = [])
    case a
    when Hash
      a_ = a.reject { |k,v| ignoring.include?(k) }
      b_ = b.reject { |k,v| ignoring.include?(k) }
      expect(a_.keys.sort).to eq b_.keys.sort
      a_.each { |k,v| match_ignoring(v, b[k], ignoring) }
    when Array
      expect(a.size).to eq b.size
      a.each_with_index do |e,i|
        match_ignoring(e.to_hash, b[i], ignoring)
      end
    when Quizzes::QuizQuestion::QuestionData
      expect(a.to_hash).to eq b
    else
      expect(a).to eq b
    end
  end

  def fname
    File.expand_path("../fixtures/spec-canvas-1.zip", __FILE__)
  end

  def setup_migration(zip_path = fname)
    @migration = ContentMigration.new(:context => @course,
                                     :user => @user)
    @migration.update_migration_settings({
      :migration_type => 'qti_converter',
      :flavor => Qti::Flavors::RESPONDUS
    })
    @migration.save!

    @attachment = Attachment.new
    @attachment.context = @migration
    @attachment.uploaded_data = File.open(zip_path, 'rb')
    @attachment.filename = 'qti_import_test1.zip'
    @attachment.save!

    @migration.attachment = @attachment
    @migration.save!
  end

  def do_migration
    Canvas::Migration::Worker::QtiWorker.new(@migration.id).perform
    @migration.reload
    expect(@migration).to be_imported
  end

  RESPONDUS_QUESTIONS =
    [{"position"=>1,
      "correct_comments"=>"This is the correct answer feedback",
      "question_type"=>"multiple_choice_question",
      "question_bank_name"=>"Instructure Question Types",
      "assessment_question_id"=>"18",
      "neutral_comments"=>"This is some general feedback.",
      "incorrect_comments"=>"This is the incorrect answer feedback",
      "migration_id"=>"QUE_1006",
      "points_possible"=>1.5,
      "question_name"=>"MC Question 1",
      "answers"=>
       [{"comments"=>"choice 1 feedback",
         "migration_id"=>"QUE_1008_A1",
         "text"=>"Answer choice 1",
         "weight"=>100,
         "id"=>304},
        {"comments"=>"choice 2 feedback",
         "migration_id"=>"QUE_1009_A2",
         "text"=>"Answer choice 2",
         "weight"=>0,
         "id"=>6301},
        {"comments"=>"choice 3 feedback",
         "migration_id"=>"QUE_1010_A3",
         "text"=>"Answer choice 3",
         "weight"=>0,
         "id"=>6546},
        {"comments"=>"choice 4 feedback",
         "migration_id"=>"QUE_1011_A4",
         "text"=>"Answer choice 4",
         "weight"=>0,
         "id"=>9001}],
      "question_text"=>
       "This is the question text.<br>\nThese are some symbol font characters: <span style=\"font-size: 12pt;\">∂♥∃Δƒ</span>"},
     {"position"=>2,
      "correct_comments"=>"correct answer feedback",
      "question_type"=>"true_false_question",
      "question_bank_name"=>"Instructure Question Types",
      "assessment_question_id"=>"19",
      "neutral_comments"=>"general feedback",
      "incorrect_comments"=>"incorrect answer feedback",
      "migration_id"=>"QUE_1019",
      "points_possible"=>1,
      "question_name"=>"TF Question 1",
      "answers"=>
       [{"comments"=>"true answer feedback",
         "migration_id"=>"QUE_1021_A1",
         "text"=>"True",
         "weight"=>100,
         "id"=>55},
        {"comments"=>"false answer feedback",
         "migration_id"=>"QUE_1022_A2",
         "text"=>"False",
         "weight"=>0,
         "id"=>3501}],
      "question_text"=>"This is the question wording."},
     {"position"=>3,
      "correct_comments"=>"correct feed",
      "question_type"=>"short_answer_question",
      "question_bank_name"=>"Instructure Question Types",
      "assessment_question_id"=>"20",
      "neutral_comments"=>"general feed",
      "incorrect_comments"=>"incorrect feed",
      "migration_id"=>"QUE_1028",
      "points_possible"=>1,
      "question_name"=>"FIB Question 1",
      "answers"=>
       [{"comments"=>"", "text"=>"correct answer 1", "weight"=>100, "id"=>4954},
        {"comments"=>"", "text"=>"correct answer 2", "weight"=>100, "id"=>6688}],
      "question_text"=>"This is the question text."},
     {"position"=>4,
      "correct_comments"=>"correct feed",
      "question_type"=>"fill_in_multiple_blanks_question",
      "question_bank_name"=>"Instructure Question Types",
      "assessment_question_id"=>"21",
      "neutral_comments"=>"general feed",
      "incorrect_comments"=>"incorrect feed",
      "migration_id"=>"QUE_1034",
      "points_possible"=>2,
      "question_name"=>"FIMB Question 1",
      "answers"=>
       [{"text"=>"question", "weight"=>100, "id"=>346, "blank_id"=>"a"},
        {"text"=>"interrogative", "weight"=>100, "id"=>7169, "blank_id"=>"a"},
        {"text"=>"Fill in Multiple Blanks",
         "weight"=>100,
         "id"=>1578,
         "blank_id"=>"b"}],
      "question_text"=>"This is the [a] wording for a [b] question."},
     {"position"=>5,
      "correct_comments"=>"correct feed",
      "question_type"=>"multiple_answers_question",
      "question_bank_name"=>"Instructure Question Types",
      "assessment_question_id"=>"22",
      "neutral_comments"=>"general feed",
      "incorrect_comments"=>"incorrect feed",
      "migration_id"=>"QUE_1038",
      "points_possible"=>2,
      "question_name"=>"MA Question 1",
      "answers"=>
       [{"comments"=>"choice feed 1",
         "migration_id"=>"QUE_1040_A1",
         "text"=>"This is incorrect answer 1",
         "weight"=>0,
         "id"=>1897},
        {"comments"=>"choice feed 2",
         "migration_id"=>"QUE_1041_A2",
         "text"=>"This is correct answer 1",
         "weight"=>100,
         "id"=>1865},
        {"comments"=>"choice feed 3",
         "migration_id"=>"QUE_1042_A3",
         "text"=>"This is incorrect answer 2",
         "weight"=>0,
         "id"=>8381},
        {"comments"=>"choice feed 4",
         "migration_id"=>"QUE_1043_A4",
         "text"=>"This is correct answer 2",
         "weight"=>100,
         "id"=>9111}],
      "question_text"=>"This is the question text."},
     {"position"=>6,
      "correct_comments"=>"correct feed",
      "question_type"=>"numerical_question",
      "question_bank_name"=>"Instructure Question Types",
      "assessment_question_id"=>"23",
      "neutral_comments"=>"general feed",
      "incorrect_comments"=>"incorrect feed",
      "migration_id"=>"QUE_1051",
      "points_possible"=>1,
      "question_name"=>"NA Question 1",
      "answers"=>
       [{"comments"=>"",
         "numerical_answer_type"=>"range_answer",
         "weight"=>100,
         "end"=>1.3,
         "id"=>9082,
         "start"=>1.2}],
      "question_text"=>"This is the question wording."},
     {"position"=>7,
      "correct_comments"=>"",
      "question_type"=>"text_only_question",
      "question_bank_name"=>"Instructure Question Types",
      "assessment_question_id"=>"24",
      "incorrect_comments"=>"",
      "migration_id"=>"QUE_1053",
      "points_possible"=>1,
      "question_name"=>"TX Question 1",
      "answers"=>[],
      "question_text"=>"This is the question wording."},
     {"position"=>8,
      "correct_comments"=>"",
      "question_type"=>"essay_question",
      "question_bank_name"=>"Instructure Question Types",
      "assessment_question_id"=>"25",
      "neutral_comments"=>"correct answer feedback",
      "incorrect_comments"=>"",
      "migration_id"=>"QUE_1054",
      "points_possible"=>1,
      "question_name"=>"ES Question 1",
      "answers"=>[],
      "question_text"=>"This is the question text."},
     {"position"=>9,
      "correct_comments"=>"correct feed",
      "question_type"=>"matching_question",
      "question_bank_name"=>"Instructure Question Types",
      "assessment_question_id"=>"26",
      "neutral_comments"=>"general feed",
      "incorrect_comments"=>"incorrect feed",
      "migration_id"=>"QUE_1061",
      "points_possible"=>1,
      "question_name"=>"MT Question 1",
      "answers"=>
       [{"comments"=>"",
         "match_id"=>342,
         "text"=>"Matching left side 1",
         "left"=>"Matching left side 1",
         "id"=>2740,
         "right"=>"Matching right side 1"},
        {"comments"=>"",
         "match_id"=>8808,
         "text"=>"Matching L2",
         "left"=>"Matching L2",
         "id"=>6479,
         "right"=>"Matching right side 2"},
        {"comments"=>"",
         "match_id"=>9565,
         "text"=>"Matching left side 3",
         "left"=>"Matching left side 3",
         "id"=>3074,
         "right"=>"Matching right side 3"},
        {"comments"=>"",
         "match_id"=>1142,
         "text"=>"Matching left side 4",
         "left"=>"Matching left side 4",
         "id"=>7696,
         "right"=>"Matching right side 4"}],
      "matches"=>
       [{"match_id"=>342, "text"=>"Matching right side 1"},
        {"match_id"=>8808, "text"=>"Matching right side 2"},
        {"match_id"=>9565, "text"=>"Matching right side 3"},
        {"match_id"=>1142, "text"=>"Matching right side 4"},
        {"match_id"=>5875, "text"=>"Distractor 1"},
        {"match_id"=>2330, "text"=>"Distractor 2"}],
      "question_text"=>"This is the question text."}]
end

end
