"""
Gitlab API: https://docs.gitlab.com/ee/api/merge_request_approvals.html
"""

import copy

import pytest
import responses

import gitlab

approval_rule_id = 1
approval_rule_name = "security"
approvals_required = 3
user_ids = [5, 50]
group_ids = [5]

new_approval_rule_name = "new approval rule"
new_approval_rule_user_ids = user_ids
new_approval_rule_approvals_required = 2

updated_approval_rule_user_ids = [5]
updated_approval_rule_approvals_required = 1


@pytest.fixture
def resp_snippet():
    merge_request_content = [
        {
            "id": 1,
            "iid": 1,
            "project_id": 1,
            "title": "test1",
            "description": "fixed login page css paddings",
            "state": "merged",
            "merged_by": {
                "id": 87854,
                "name": "Douwe Maan",
                "username": "DouweM",
                "state": "active",
                "avatar_url": "https://gitlab.example.com/uploads/-/system/user/avatar/87854/avatar.png",
                "web_url": "https://gitlab.com/DouweM",
            },
            "merged_at": "2018-09-07T11:16:17.520Z",
            "closed_by": None,
            "closed_at": None,
            "created_at": "2017-04-29T08:46:00Z",
            "updated_at": "2017-04-29T08:46:00Z",
            "target_branch": "master",
            "source_branch": "test1",
            "upvotes": 0,
            "downvotes": 0,
            "author": {
                "id": 1,
                "name": "Administrator",
                "username": "admin",
                "state": "active",
                "avatar_url": None,
                "web_url": "https://gitlab.example.com/admin",
            },
            "assignee": {
                "id": 1,
                "name": "Administrator",
                "username": "admin",
                "state": "active",
                "avatar_url": None,
                "web_url": "https://gitlab.example.com/admin",
            },
            "assignees": [
                {
                    "name": "Miss Monserrate Beier",
                    "username": "axel.block",
                    "id": 12,
                    "state": "active",
                    "avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
                    "web_url": "https://gitlab.example.com/axel.block",
                }
            ],
            "source_project_id": 2,
            "target_project_id": 3,
            "labels": ["Community contribution", "Manage"],
            "work_in_progress": None,
            "milestone": {
                "id": 5,
                "iid": 1,
                "project_id": 3,
                "title": "v2.0",
                "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.",
                "state": "closed",
                "created_at": "2015-02-02T19:49:26.013Z",
                "updated_at": "2015-02-02T19:49:26.013Z",
                "due_date": "2018-09-22",
                "start_date": "2018-08-08",
                "web_url": "https://gitlab.example.com/my-group/my-project/milestones/1",
            },
            "merge_when_pipeline_succeeds": None,
            "merge_status": "can_be_merged",
            "sha": "8888888888888888888888888888888888888888",
            "merge_commit_sha": None,
            "squash_commit_sha": None,
            "user_notes_count": 1,
            "discussion_locked": None,
            "should_remove_source_branch": True,
            "force_remove_source_branch": False,
            "allow_collaboration": False,
            "allow_maintainer_to_push": False,
            "web_url": "http://gitlab.example.com/my-group/my-project/merge_requests/1",
            "references": {
                "short": "!1",
                "relative": "my-group/my-project!1",
                "full": "my-group/my-project!1",
            },
            "time_stats": {
                "time_estimate": 0,
                "total_time_spent": 0,
                "human_time_estimate": None,
                "human_total_time_spent": None,
            },
            "squash": False,
            "task_completion_status": {"count": 0, "completed_count": 0},
        }
    ]
    mr_ars_content = [
        {
            "id": approval_rule_id,
            "name": approval_rule_name,
            "rule_type": "regular",
            "eligible_approvers": [
                {
                    "id": user_ids[0],
                    "name": "John Doe",
                    "username": "jdoe",
                    "state": "active",
                    "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
                    "web_url": "http://localhost/jdoe",
                },
                {
                    "id": user_ids[1],
                    "name": "Group Member 1",
                    "username": "group_member_1",
                    "state": "active",
                    "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
                    "web_url": "http://localhost/group_member_1",
                },
            ],
            "approvals_required": approvals_required,
            "source_rule": None,
            "users": [
                {
                    "id": 5,
                    "name": "John Doe",
                    "username": "jdoe",
                    "state": "active",
                    "avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
                    "web_url": "http://localhost/jdoe",
                }
            ],
            "groups": [
                {
                    "id": 5,
                    "name": "group1",
                    "path": "group1",
                    "description": "",
                    "visibility": "public",
                    "lfs_enabled": False,
                    "avatar_url": None,
                    "web_url": "http://localhost/groups/group1",
                    "request_access_enabled": False,
                    "full_name": "group1",
                    "full_path": "group1",
                    "parent_id": None,
                    "ldap_cn": None,
                    "ldap_access": None,
                }
            ],
            "contains_hidden_groups": False,
            "overridden": False,
        }
    ]

    with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps:
        rsps.add(
            method=responses.GET,
            url="http://localhost/api/v4/projects/1/merge_requests",
            json=merge_request_content,
            content_type="application/json",
            status=200,
        )
        rsps.add(
            method=responses.GET,
            url="http://localhost/api/v4/projects/1/merge_requests/1",
            json=merge_request_content[0],
            content_type="application/json",
            status=200,
        )
        rsps.add(
            method=responses.GET,
            url="http://localhost/api/v4/projects/1/merge_requests/1/approval_rules",
            json=mr_ars_content,
            content_type="application/json",
            status=200,
        )

        new_mr_ars_content = dict(mr_ars_content[0])
        new_mr_ars_content["name"] = new_approval_rule_name
        new_mr_ars_content["approvals_required"] = new_approval_rule_approvals_required

        rsps.add(
            method=responses.POST,
            url="http://localhost/api/v4/projects/1/merge_requests/1/approval_rules",
            json=new_mr_ars_content,
            content_type="application/json",
            status=200,
        )

        updated_mr_ars_content = copy.deepcopy(mr_ars_content[0])
        updated_mr_ars_content["eligible_approvers"] = [
            mr_ars_content[0]["eligible_approvers"][0]
        ]

        updated_mr_ars_content[
            "approvals_required"
        ] = updated_approval_rule_approvals_required

        rsps.add(
            method=responses.PUT,
            url="http://localhost/api/v4/projects/1/merge_requests/1/approval_rules/1",
            json=updated_mr_ars_content,
            content_type="application/json",
            status=200,
        )
        yield rsps


def test_project_approval_manager_update_uses_post(project, resp_snippet):
    """Ensure the
    gitlab.v4.objects.merge_request_approvals.ProjectApprovalManager object has
    _update_uses_post set to True"""
    approvals = project.approvals
    assert isinstance(
        approvals, gitlab.v4.objects.merge_request_approvals.ProjectApprovalManager
    )
    assert approvals._update_uses_post is True


def test_list_merge_request_approval_rules(project, resp_snippet):
    approval_rules = project.mergerequests.get(1).approval_rules.list()
    assert len(approval_rules) == 1
    assert approval_rules[0].name == approval_rule_name
    assert approval_rules[0].id == approval_rule_id


def test_update_merge_request_approvals_set_approvers(project, resp_snippet):
    approvals = project.mergerequests.get(1).approvals
    assert isinstance(
        approvals,
        gitlab.v4.objects.merge_request_approvals.ProjectMergeRequestApprovalManager,
    )
    assert approvals._update_uses_post is True
    response = approvals.set_approvers(
        updated_approval_rule_approvals_required,
        approver_ids=updated_approval_rule_user_ids,
        approver_group_ids=group_ids,
        approval_rule_name=approval_rule_name,
    )

    assert response.approvals_required == updated_approval_rule_approvals_required
    assert len(response.eligible_approvers) == len(updated_approval_rule_user_ids)
    assert response.eligible_approvers[0]["id"] == updated_approval_rule_user_ids[0]
    assert response.name == approval_rule_name


def test_create_merge_request_approvals_set_approvers(project, resp_snippet):
    approvals = project.mergerequests.get(1).approvals
    assert isinstance(
        approvals,
        gitlab.v4.objects.merge_request_approvals.ProjectMergeRequestApprovalManager,
    )
    assert approvals._update_uses_post is True
    response = approvals.set_approvers(
        new_approval_rule_approvals_required,
        approver_ids=new_approval_rule_user_ids,
        approver_group_ids=group_ids,
        approval_rule_name=new_approval_rule_name,
    )
    assert response.approvals_required == new_approval_rule_approvals_required
    assert len(response.eligible_approvers) == len(new_approval_rule_user_ids)
    assert response.eligible_approvers[0]["id"] == new_approval_rule_user_ids[0]
    assert response.name == new_approval_rule_name


def test_create_merge_request_approval_rule(project, resp_snippet):
    approval_rules = project.mergerequests.get(1).approval_rules
    data = {
        "name": new_approval_rule_name,
        "approvals_required": new_approval_rule_approvals_required,
        "rule_type": "regular",
        "user_ids": new_approval_rule_user_ids,
        "group_ids": group_ids,
    }
    response = approval_rules.create(data)
    assert response.approvals_required == new_approval_rule_approvals_required
    assert len(response.eligible_approvers) == len(new_approval_rule_user_ids)
    assert response.eligible_approvers[0]["id"] == new_approval_rule_user_ids[0]
    assert response.name == new_approval_rule_name


def test_update_merge_request_approval_rule(project, resp_snippet):
    approval_rules = project.mergerequests.get(1).approval_rules
    ar_1 = approval_rules.list()[0]
    ar_1.user_ids = updated_approval_rule_user_ids
    ar_1.approvals_required = updated_approval_rule_approvals_required
    ar_1.save()

    assert ar_1.approvals_required == updated_approval_rule_approvals_required
    assert len(ar_1.eligible_approvers) == len(updated_approval_rule_user_ids)
    assert ar_1.eligible_approvers[0]["id"] == updated_approval_rule_user_ids[0]