from infrastructure.models import User
from tests.base import PASSWORD, CoreTestCase


class MemberEditTests(CoreTestCase):
    def patch(self, actor, org, member, body):
        return self.api(actor, org).patch(f"/api/v1/members/{member.pk}/", body, format="json")

    def test_manager_edits_name_code_username_mobile_and_password(self):
        m = self.membership(self.employee_a, self.org_a)
        body = {"name": "New Name", "personnel_code": "E-77", "username": "New.User", "mobile": "09121234567", "password": "An0ther-pass!"}
        r = self.patch(self.manager_a, self.org_a, m, body)
        self.assertEqual(r.status_code, 200, r.data)
        u = User.objects.get(pk=self.employee_a.pk)
        self.assertEqual((u.name, u.username, u.mobile), ("New Name", "new.user", "09121234567"))
        self.assertIsNone(u.mobile_verified_at)
        m.refresh_from_db()
        self.assertEqual(m.personnel_code, "E-77")
        login = self.api().post("/api/v1/auth/login/", {"identifier": "new.user", "password": "An0ther-pass!"}, format="json")
        self.assertEqual(login.status_code, 200)

    def test_employee_cannot_edit_anyone(self):
        m = self.membership(self.manager_a2, self.org_a)
        self.assertEqual(self.patch(self.employee_a, self.org_a, m, {"name": "x"}).status_code, 403)

    def test_shared_account_login_details_are_protected(self):
        # `multi` is a member of A and B: manager A may rename but not change login details
        m = self.membership(self.multi, self.org_a)
        self.assertEqual(self.patch(self.manager_a, self.org_a, m, {"name": "Renamed"}).status_code, 200)
        r = self.patch(self.manager_a, self.org_a, m, {"password": "An0ther-pass!"})
        self.assertEqual(r.status_code, 400)
        self.assertFalse(User.objects.get(pk=self.multi.pk).check_password("An0ther-pass!"))
        self.assertEqual(self.patch(self.manager_a, self.org_a, m, {"username": "hijack"}).status_code, 400)

    def test_cannot_change_own_login_details(self):
        m = self.membership(self.manager_a, self.org_a)
        self.assertEqual(self.patch(self.manager_a, self.org_a, m, {"password": "An0ther-pass!"}).status_code, 400)
        self.assertEqual(self.patch(self.manager_a, self.org_a, m, {"name": "Me"}).status_code, 200)

    def test_cannot_edit_member_of_another_org(self):
        other = self.membership(self.employee_b, self.org_b)
        self.assertEqual(self.patch(self.manager_a, self.org_a, other, {"name": "x"}).status_code, 404)

    def test_uniqueness_and_validation(self):
        m = self.membership(self.employee_a, self.org_a)
        taken = self.patch(self.manager_a, self.org_a, m, {"username": "manager-a"})  # collides with a personnel_code
        self.assertEqual(taken.status_code, 400)
        self.assertEqual(self.patch(self.manager_a, self.org_a, m, {"username": "ab"}).status_code, 400)
        self.assertEqual(self.patch(self.manager_a, self.org_a, m, {"mobile": "123"}).status_code, 400)
        self.assertEqual(self.patch(self.manager_a, self.org_a, m, {"password": "1"}).status_code, 400)
        mgr = self.membership(self.manager_a, self.org_a)
        mgr.personnel_code = "DUP"
        mgr.save()
        self.assertEqual(self.patch(self.manager_a2, self.org_a, m, {"personnel_code": "DUP"}).status_code, 400)

    def test_edit_is_audited_without_secrets(self):
        from apps.audit.models import AuditLog

        m = self.membership(self.employee_a, self.org_a)
        self.patch(self.manager_a, self.org_a, m, {"password": PASSWORD + "x"})
        row = AuditLog.objects.filter(action="member.updated").latest("id")
        self.assertEqual(row.after, {"fields": ["password"]})

    def test_manager_can_mark_mobile_verified_so_mobile_login_works(self):
        m = self.membership(self.employee_a, self.org_a)
        self.patch(self.manager_a, self.org_a, m, {"mobile": "09390705063"})
        body = {"identifier": "09390705063", "password": PASSWORD}
        self.assertEqual(self.api().post("/api/v1/auth/login/", body, format="json").status_code, 401)
        self.assertEqual(self.patch(self.manager_a, self.org_a, m, {"mobile_verified": True}).status_code, 200)
        self.assertEqual(self.api().post("/api/v1/auth/login/", body, format="json").status_code, 200)
        self.patch(self.manager_a, self.org_a, m, {"mobile_verified": False})
        self.assertEqual(self.api().post("/api/v1/auth/login/", body, format="json").status_code, 401)

    def test_mobile_verification_rules(self):
        m = self.membership(self.employee_a, self.org_a)
        self.assertEqual(self.patch(self.manager_a, self.org_a, m, {"mobile_verified": True}).status_code, 400)  # no mobile
        shared = self.membership(self.multi, self.org_a)
        User.objects.filter(pk=self.multi.pk).update(mobile="09121111111")
        self.assertEqual(self.patch(self.manager_a, self.org_a, shared, {"mobile_verified": True}).status_code, 400)
        mine = self.membership(self.manager_a, self.org_a)
        self.assertEqual(self.patch(self.manager_a, self.org_a, mine, {"mobile_verified": True}).status_code, 400)
        self.assertEqual(self.patch(self.employee_a, self.org_a, self.membership(self.manager_a2, self.org_a), {"mobile_verified": True}).status_code, 403)