# frozen_string_literal: true

require 'spec_helper'

describe API::ManagedLicenses do
  set(:project) { create(:project, :public) }
  set(:maintainer_user) { create(:user) }
  set(:dev_user) { create(:user) }
  set(:reporter_user) { create(:user) }
  set(:software_license_policy) { create(:software_license_policy, project: project) }

  before do
    stub_licensed_features(license_management: true)
    project.add_maintainer(maintainer_user)
    project.add_developer(dev_user)
    project.add_reporter(reporter_user)
  end

  describe 'GET /projects/:id/managed_licenses' do
    context 'with license management not available' do
      before do
        stub_licensed_features(license_management: false)
      end

      it 'returns a forbidden status' do
        get api("/projects/#{project.id}/managed_licenses", dev_user)

        expect(response).to have_gitlab_http_status(403)
      end
    end

    context 'with an authorized user with proper permissions' do
      it 'returns project managed licenses' do
        get api("/projects/#{project.id}/managed_licenses", dev_user)

        expect(response).to have_gitlab_http_status(200)
        expect(response).to match_response_schema('managed_licenses', dir: 'ee')
        expect(json_response).to be_a(Array)
        expect(json_response.first['id']).to eq(software_license_policy.id)
        expect(json_response.first['name']).to eq(software_license_policy.name)
        expect(json_response.first['approval_status']).to eq('approved')
      end
    end

    context 'with authorized user without read permissions' do
      it 'returns project managed licenses to users with read permissions' do
        get api("/projects/#{project.id}/managed_licenses", reporter_user)

        expect(response).to have_gitlab_http_status(200)
        expect(response).to match_response_schema('managed_licenses', dir: 'ee')
        expect(json_response).to be_a(Array)
        expect(json_response.first['id']).to eq(software_license_policy.id)
        expect(json_response.first['name']).to eq(software_license_policy.name)
        expect(json_response.first['approval_status']).to eq('approved')
      end
    end

    context 'with unauthorized user' do
      it 'returns project managed licenses for public project' do
        get api("/projects/#{project.id}/managed_licenses")

        expect(response).to have_gitlab_http_status(200)
        expect(response).to match_response_schema('managed_licenses', dir: 'ee')
      end

      it 'responses with 404 Not Found for not existing project' do
        get api("/projects/0/managed_licenses")

        expect(response).to have_gitlab_http_status(404)
      end

      context 'when project is private' do
        before do
          project.update!(visibility_level: 'private')
        end

        it 'responses with 404 Not Found' do
          get api("/projects/#{project.id}/managed_licenses")

          expect(response).to have_gitlab_http_status(404)
        end
      end
    end
  end

  describe 'GET /projects/:id/managed_licenses/:managed_license_id' do
    context 'authorized user with proper permissions' do
      it 'returns project managed license details' do
        get api("/projects/#{project.id}/managed_licenses/#{software_license_policy.id}", dev_user)

        expect(response).to have_gitlab_http_status(200)
        expect(response).to match_response_schema('software_license_policy', dir: 'ee')
        expect(json_response['id']).to eq(software_license_policy.id)
        expect(json_response['name']).to eq(software_license_policy.name)
        expect(json_response['approval_status']).to eq('approved')
      end

      it 'returns project managed license details using the license name as key' do
        escaped_name = CGI.escape(software_license_policy.name)
        get api("/projects/#{project.id}/managed_licenses/#{escaped_name}", dev_user)

        expect(response).to have_gitlab_http_status(200)
        expect(response).to match_response_schema('software_license_policy', dir: 'ee')
        expect(json_response['id']).to eq(software_license_policy.id)
        expect(json_response['name']).to eq(software_license_policy.name)
        expect(json_response['approval_status']).to eq('approved')
      end

      it 'responds with 404 Not Found if requesting non-existing managed license' do
        get api("/projects/#{project.id}/managed_licenses/1234512345", dev_user)

        expect(response).to have_gitlab_http_status(404)
      end
    end

    context 'authorized user with read permissions' do
      it 'returns project managed license details' do
        get api("/projects/#{project.id}/managed_licenses/#{software_license_policy.id}", reporter_user)

        expect(response).to have_gitlab_http_status(200)
        expect(response).to match_response_schema('software_license_policy', dir: 'ee')
        expect(json_response['id']).to eq(software_license_policy.id)
        expect(json_response['name']).to eq(software_license_policy.name)
        expect(json_response['approval_status']).to eq('approved')
      end
    end

    context 'unauthorized user' do
      it 'does not return project managed license details' do
        get api("/projects/#{project.id}/managed_licenses/#{software_license_policy.id}")

        expect(response).to have_gitlab_http_status(401)
      end
    end
  end

  describe 'POST /projects/:id/managed_licenses' do
    context 'authorized user with proper permissions' do
      it 'creates managed license' do
        expect do
          post api("/projects/#{project.id}/managed_licenses", maintainer_user),
            params: {
              name: 'NEW_LICENSE_NAME',
              approval_status: 'approved'
            }
        end.to change {project.software_license_policies.count}.by(1)

        expect(response).to have_gitlab_http_status(201)
        expect(response).to match_response_schema('software_license_policy', dir: 'ee')
        expect(json_response).to have_key('id')
        expect(json_response['name']).to eq('NEW_LICENSE_NAME')
        expect(json_response['approval_status']).to eq('approved')
      end

      it 'does not allow to duplicate managed license name' do
        expect do
          post api("/projects/#{project.id}/managed_licenses", maintainer_user),
            params: {
              name: software_license_policy.name,
              approval_status: 'blacklisted'
            }
        end.not_to change {project.software_license_policies.count}

        expect(response).to have_gitlab_http_status(400)
      end
    end

    context 'authorized user with read permissions' do
      it 'does not create managed license' do
        post api("/projects/#{project.id}/managed_licenses", dev_user),
          params: {
            name: 'NEW_LICENSE_NAME',
            approval_status: 'approved'
          }

        expect(response).to have_gitlab_http_status(403)
      end
    end

    context 'authorized user without permissions' do
      it 'does not create managed license' do
        post api("/projects/#{project.id}/managed_licenses", reporter_user),
          params: {
            name: 'NEW_LICENSE_NAME',
            approval_status: 'approved'
          }

        expect(response).to have_gitlab_http_status(403)
      end
    end

    context 'unauthorized user' do
      it 'does not create managed license' do
        post api("/projects/#{project.id}/managed_licenses"),
          params: {
            name: 'NEW_LICENSE_NAME',
            approval_status: 'approved'
          }

        expect(response).to have_gitlab_http_status(401)
      end
    end
  end

  describe 'PATCH /projects/:id/managed_licenses/:managed_license_id' do
    context 'authorized user with proper permissions' do
      it 'updates managed license data' do
        initial_license = project.software_license_policies.first
        initial_id = initial_license.id
        initial_name = initial_license.name
        initial_classification = initial_license.classification
        patch api("/projects/#{project.id}/managed_licenses/#{software_license_policy.id}", maintainer_user),
          params: { approval_status: 'blacklisted' }

        updated_software_license_policy = project.software_license_policies.reload.first

        expect(response).to have_gitlab_http_status(200)
        expect(response).to match_response_schema('software_license_policy', dir: 'ee')

        # Check that response is equal to the updated object
        expect(json_response['id']).to eq(initial_id)
        expect(json_response['name']).to eq(updated_software_license_policy.name)
        expect(json_response['approval_status']).to eq('blacklisted')

        # Check that the approval status was updated
        expect(updated_software_license_policy).to be_denied

        # Check that response is equal to the old object except for the approval status
        expect(initial_id).to eq(updated_software_license_policy.id)
        expect(initial_name).to eq(updated_software_license_policy.name)
        expect(initial_classification).not_to eq(updated_software_license_policy.classification)
      end

      it 'responds with 404 Not Found if requesting non-existing managed license' do
        patch api("/projects/#{project.id}/managed_licenses/1234512345", maintainer_user)

        expect(response).to have_gitlab_http_status(404)
      end
    end

    context 'authorized user with read permissions' do
      it 'does not update managed license' do
        patch api("/projects/#{project.id}/managed_licenses/#{software_license_policy.id}", dev_user)

        expect(response).to have_gitlab_http_status(403)
      end
    end

    context 'authorized user without permissions' do
      it 'does not update managed license' do
        patch api("/projects/#{project.id}/managed_licenses/#{software_license_policy.id}", reporter_user)

        expect(response).to have_gitlab_http_status(403)
      end
    end

    context 'unauthorized user' do
      it 'does not update managed license' do
        patch api("/projects/#{project.id}/managed_licenses/#{software_license_policy.id}")

        expect(response).to have_gitlab_http_status(401)
      end
    end
  end

  describe 'DELETE /projects/:id/managed_licenses/:managed_license_id' do
    context 'authorized user with proper permissions' do
      it 'deletes managed license' do
        expect do
          delete api("/projects/#{project.id}/managed_licenses/#{software_license_policy.id}", maintainer_user)

          expect(response).to have_gitlab_http_status(204)
        end.to change {project.software_license_policies.count}.by(-1)
      end

      it 'responds with 404 Not Found if requesting non-existing managed license' do
        expect do
          delete api("/projects/#{project.id}/managed_licenses/1234512345", maintainer_user)

          expect(response).to have_gitlab_http_status(404)
        end.not_to change {project.software_license_policies.count}
      end
    end

    context 'authorized user with read permissions' do
      it 'does not delete managed license' do
        expect do
          delete api("/projects/#{project.id}/managed_licenses/#{software_license_policy.id}", dev_user)

          expect(response).to have_gitlab_http_status(403)
        end.not_to change {project.software_license_policies.count}
      end
    end

    context 'authorized user without permissions' do
      it 'does not delete managed license' do
        expect do
          delete api("/projects/#{project.id}/managed_licenses/#{software_license_policy.id}", reporter_user)

          expect(response).to have_gitlab_http_status(403)
        end.not_to change {project.software_license_policies.count}
      end
    end

    context 'unauthorized user' do
      it 'does not delete managed license' do
        expect do
          delete api("/projects/#{project.id}/managed_licenses/#{software_license_policy.id}")

          expect(response).to have_gitlab_http_status(401)
        end.not_to change {project.software_license_policies.count}
      end
    end
  end
end
