# frozen_string_literal: true

#
# Copyright (C) 2017 - 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__) + '/lti2_api_spec_helper')
require File.expand_path(File.dirname(__FILE__) + '/../api_spec_helper')

require_dependency "lti/ims/access_token_helper"
require_dependency "lti/users_api_controller"
module Lti
  describe UsersApiController, type: :request do
    include_context 'lti2_api_spec_helper'

    let(:authorized_services) do
      [
        {"service"=>"vnd.Canvas.User", "action"=>["GET"], "@type"=>"RestServiceProfile"},
        {"service"=>"vnd.Canvas.GroupIndex", "action"=>["GET"], "@type"=>"RestServiceProfile"}
      ]
    end

    let(:assignment) do
      a = course.assignments.new(:title => "some assignment")
      a.workflow_state = "published"
      a.tool_settings_tool = message_handler
      a.save!
      a
    end

    before do
      message_handler.update(capabilities: [Lti::ResourcePlacement::SIMILARITY_DETECTION_LTI2])
      tool_proxy.raw_data['security_contract']['tool_service'] = authorized_services
      tool_proxy.save!
      assignment.tool_settings_tool = message_handler
      assignment.save!
    end

    describe '#show' do
      let(:service_name) { UsersApiController::USER_SERVICE }
      let(:canvas_id_endpoint) { "/api/lti/users/#{student.id}" }
      let(:student) do
        course_with_student(active_all: true, course: course)
        @student.update(lti_context_id: SecureRandom.uuid)
        @student
      end
      let(:expected_student) do
        {
          "id" => student.id,
          "created_at" => @student.created_at.iso8601,
          "name" => student.name,
          "sortable_name" => student.sortable_name,
          "short_name" => student.short_name,
          "lti_id" =>  student.lti_context_id,
          "email" => student.email
        }
      end

      it 'verifies the tool has the required services' do
        tool_proxy.raw_data['security_contract']['tool_service'] = []
        tool_proxy.save!
        get canvas_id_endpoint, params: {id: student.id}, headers: request_headers
        expect(response).to be_unauthorized
      end

      it "verifies the tool is associated with at least one of the user's assignments" do
        second_course = Course.create!(name: 'second course')
        assignment.update!(course: second_course)
        get canvas_id_endpoint, params: {id: student.id}, headers: request_headers
        expect(response).to be_unauthorized
      end

      it 'does not grant access if the tool and the user have no associated assignments' do
        assignment.destroy!
        get canvas_id_endpoint, params: {id: student.id}, headers: request_headers
        expect(response).to be_unauthorized
      end

      context 'course' do
        before do
          tool_proxy.update!(context: course)
        end

        it 'returns a user by lti id' do
          get canvas_id_endpoint, params: {id: student.lti_context_id}, headers: request_headers
          parsed_body = JSON.parse(response.body)
          expect(parsed_body).to eq expected_student
        end

        it 'returns a user by old lti id' do
          UserPastLtiId.create!(user: student, context: course, user_lti_id: student.lti_id, user_lti_context_id: 'old_lti_id', user_uuid: 'old')
          get canvas_id_endpoint, params: {id: 'old_lti_id'}, headers: request_headers
          parsed_body = JSON.parse(response.body)
          new_expected_student = expected_student
          new_expected_student['lti_id'] = 'old_lti_id'
          expect(parsed_body).to eq expected_student
        end

        it 'returns a user by Canvas id' do
          get canvas_id_endpoint, params: {id: student.id}, headers: request_headers
          parsed_body = JSON.parse(response.body)
          expect(parsed_body).to eq expected_student
        end


        it 'does not grant access if the course is inactive and the user has no associated assignments' do
          id = student.id
          course.destroy!
          get canvas_id_endpoint, params: {id: id}, headers: request_headers
          expect(response).to be_unauthorized
        end
      end

      context 'account' do
        it 'returns a user by lti id' do
          get canvas_id_endpoint, params: {id: student.lti_context_id}, headers: request_headers
          parsed_body = JSON.parse(response.body)
          expect(parsed_body).to eq expected_student
        end

        it 'returns a user by Canvas id' do
          get canvas_id_endpoint, params: {id: student.id}, headers: request_headers
          parsed_body = JSON.parse(response.body)
          expect(parsed_body).to eq expected_student
        end
      end
    end

    describe '#group_index' do
      include Api::V1::User

      let(:service_name) { UsersApiController::USER_SERVICE }
      let(:course) { course_model }
      let(:group) { group_model(context: course) }
      let(:group_index_endpoint) { "/api/lti/groups/#{group.global_id}/users" }
      let(:student_lti_id) { SecureRandom.uuid }

      let(:student_one) do
        student_in_course(course: group.context)
        @student.update!(lti_context_id: student_lti_id)
        @student
      end

      let(:student_two) do
        student_in_course(course: group.context)
        @student
      end

      let(:student_three) do
        student_in_course(course: group.context)
        @student.update!(email: 'student@test.com')
        @student
      end

      before do
        group.context.update!(account: tool_proxy.account)
        group.add_user(student_one, 'accepted')
        group.add_user(student_two, 'accepted')
        group.add_user(student_three, 'accepted')
      end

      it 'returns a list of users in the specified group' do
        get group_index_endpoint, headers: request_headers
        parsed_body = JSON.parse(response.body)
        expected_json = group.users.map do |user|
          user_json(user, user, nil, [], group.context, tool_includes: %w(email lti_id))
        end
        expect(parsed_body.sort_by{|u| u[:id]}).to eq(expected_json.sort_by{|u| u[:id]})
      end

      it 'responds with 401 if group is not in tool context' do
        group.context.update!(account: account_model)
        get group_index_endpoint, headers: request_headers
        expect(response).to be_unauthorized
      end

      it 'responds with 401 if the group is not active' do
        group.update!(workflow_state: 'deleted')
        get group_index_endpoint, headers: request_headers
        expect(response).to be_unauthorized
      end

      it 'responds with 404 if group is not found' do
        get "/api/lti/groups/#{group.global_id + 1}/users", headers: request_headers
        expect(response).to be_not_found
      end

      it 'includes user lti id' do
        get group_index_endpoint, headers: request_headers
        parsed_body = JSON.parse(response.body)
        user_json = parsed_body.find { |u| u['id'] == student_one.id }
        expect(user_json['lti_id']).to eq student_one.lti_context_id
      end

      it 'does not include students who are not in the group' do
        student_in_course(course: group.context)
        get group_index_endpoint, headers: request_headers
        parsed_body = JSON.parse(response.body)
        expected_json = group.users.map do |user|
          user_json(user, user, nil, [], group.context, tool_includes: %w(email lti_id))
        end
        expect(parsed_body.sort_by{|u| u[:id]}).to eq(expected_json.sort_by{|u| u[:id]})
      end
    end
  end
end
