import unittest
from unittest.mock import patch

import api.v1.spamcheck_pb2 as spam
from vyper import v

from app.spammable import Spammable
from app.spammable.issue import Issue
from tests.app.helpers import MockContext


class TestSpam(unittest.TestCase):
    mock_issue = {
        "title": "mock spam",
        "description": "mock spam",
        "user_in_project": True,
        "project": {
            "project_id": 555,
            "project_path": "mock/spmmable",
        },
        "user": {
            "emails": [{"email": "test@example.com", "verified": True}],
            "username": "test",
            "org": "test",
            "id": 23,
            "abuse_metadata": {
                "account_age": 3,
                "spam_score": 0.32,
            },
        },
    }

    def test_project_allowed(self):
        mock_project = {123: "spamtest/hello"}
        s = Issue(spam.Issue(**self.mock_issue), None)

        allowed = s.project_allowed(555)
        self.assertTrue(allowed, "Empty allow and deny list should return True")

        s.allow_list = mock_project
        allowed = s.project_allowed(555)
        self.assertFalse(allowed, "Project not in allow_list should return False")

        allowed = s.project_allowed(123)
        self.assertTrue(allowed, "Project in allow_list should return True")

        s.allow_list = {}
        s.deny_list = mock_project
        allowed = s.project_allowed(555)
        self.assertTrue(allowed, "Project not in deny_list should return True")

        allowed = s.project_allowed(123)
        self.assertFalse(allowed, "Project in deny_list should return False")

    def test_email_allowed(self):
        def set_emails(email, verified):
            args = {"user": {"emails": [{"email": email, "verified": verified}]}}
            i = spam.Issue(**args)
            return i.user.emails

        s = Issue(spam.Issue(**self.mock_issue), None)
        Spammable.allowed_domains = {"gitlab.com"}
        emails = set_emails("integrationtest@example.com", True)
        allowed = s.email_allowed(emails)
        self.assertFalse(allowed, "Non gitlab email should not be allowed")

        emails = set_emails("integrationtest@gitlab.com", True)
        allowed = s.email_allowed(emails)
        self.assertTrue(allowed, "Verified gitlab email should be allowed")

        emails = set_emails("integrationtest@gitlab.com", False)
        allowed = s.email_allowed(emails)
        self.assertFalse(allowed, "Non-verified gitlab email should not be allowed")

    def test_user_has_id(self):
        s = spam.Issue(**self.mock_issue)
        self.assertEqual(23, s.user.id, "User ID does not match")

    def test_abuse_metadata(self):
        s = spam.Issue(**self.mock_issue)
        error_msg = "Abuse metadata has unepected value"

        self.assertEqual(3, s.user.abuse_metadata["account_age"], error_msg)
        self.assertAlmostEqual(0.32, s.user.abuse_metadata["spam_score"], msg=error_msg)

    def test_to_dict(self):
        spammable = Issue(spam.Issue(**self.mock_issue), MockContext()).to_dict()
        error_msg = "Expected field not seen in spammable dictionary"

        self.assertTrue("user" in spammable, error_msg)
        self.assertTrue("title" in spammable, error_msg)
        self.assertTrue("description" in spammable, error_msg)
        self.assertTrue("project" in spammable, error_msg)
        self.assertTrue("userInProject" in spammable, error_msg)

        user = spammable["user"]

        self.assertTrue("username" in user, error_msg)
        self.assertTrue("id" in user, error_msg)
        self.assertTrue("abuseMetadata" in user, error_msg)
        self.assertTrue("emails" in user, error_msg)
        self.assertTrue("org" in user, error_msg)

    def test_max_verdict(self):
        self.assertEqual(spam.SpamVerdict.CONDITIONAL_ALLOW, Issue.max_verdict, "Unexpected maximum verdict for Issue")

        v.set("max_issue_verdict", "ALLOW")
        Issue.set_max_verdict()
        self.assertEqual(spam.SpamVerdict.ALLOW, Issue.max_verdict, "Unexpected maximum verdict for Issue")
