"""The five views of the owner list.

"Deleted" is a soft delete: the account is deactivated and kept, so it can be
put back with its password intact. Erasing for good is a separate action,
offered only from inside the Deleted view.
"""
from datetime import timedelta

from django.contrib.auth import get_user_model
from django.test import TestCase
from django.urls import reverse
from django.utils import timezone

User = get_user_model()


def signed_in(user, when):
    """Record a real (browser) sign-in at a given moment."""
    from accounts.models import LoginEvent

    LoginEvent.objects.create(
        user=user, username=user.username, succeeded=True,
        ip="203.0.113.5", user_agent="Mozilla/5.0 (Test)",
        source=LoginEvent.WEB, occurred_at=when,
    )


class PeopleFilterTests(TestCase):
    def setUp(self):
        now = timezone.now()
        self.staff = User.objects.create_user("staff", password="pw-staff-12345", is_staff=True)
        # Staff signs in from a browser like anyone else. Worth stating: the
        # test client's own force_login deliberately does NOT count, so without
        # this the staff account reads as never having signed in.
        signed_in(self.staff, now)
        # Sign-ins are recorded as LoginEvents, not `last_login`: Django stamps
        # that field for server-side logins too, which once showed owners as
        # having signed in when they never had.
        self.recent = User.objects.create_user("recent", password="pw-1234512345")
        signed_in(self.recent, now - timedelta(days=30))

        self.lapsed = User.objects.create_user("lapsed", password="pw-1234512345")
        signed_in(self.lapsed, now - timedelta(days=400))

        self.never = User.objects.create_user("never", password="pw-1234512345")
        self.deleted = User.objects.create_user("deleted", password="pw-1234512345")
        self.deleted.is_active = False
        self.deleted.save(update_fields=["is_active"])

        self.client.force_login(self.staff)

    def names(self, **params):
        response = self.client.get(reverse("backoffice:people"), params, secure=True)
        self.assertEqual(response.status_code, 200)
        return sorted(p.username for p in response.context["people"])

    def test_all_current_is_everyone_except_the_deleted(self):
        self.assertEqual(self.names(), ["lapsed", "never", "recent", "staff"])

    def test_owners_excludes_staff(self):
        self.assertEqual(self.names(show="owners"), ["lapsed", "never", "recent"])

    def test_staff_is_only_staff(self):
        self.assertEqual(self.names(show="staff"), ["staff"])

    def test_active_means_signed_in_within_the_year(self):
        """The boundary is the point of the filter, so both sides are asserted.

        Someone who has never signed in is not active — a missing last_login
        must not read as recent. `staff` is in the expected list because
        logging them in for this test is itself a recent sign-in.
        """
        self.assertEqual(self.names(show="active"), ["recent", "staff"])

    def test_active_excludes_a_deleted_account_that_signed_in_recently(self):
        signed_in(self.deleted, timezone.now() - timedelta(days=2))
        self.assertNotIn("deleted", self.names(show="active"))

    def test_deleted_shows_only_deactivated_accounts(self):
        self.assertEqual(self.names(show="deleted"), ["deleted"])

    def test_an_unknown_filter_falls_back_to_all_current(self):
        self.assertEqual(self.names(show="nonsense"), ["lapsed", "never", "recent", "staff"])

    def test_a_search_narrows_the_view_without_moving_the_counts(self):
        response = self.client.get(reverse("backoffice:people"), {"q": "recent"}, secure=True)
        self.assertEqual([p.username for p in response.context["people"]], ["recent"])
        counts = {f["key"]: f["count"] for f in response.context["filters"]}
        self.assertEqual(counts, {"": 4, "owners": 3, "staff": 1, "active": 2, "deleted": 1})

    # ---- the two deletes ----
    def test_delete_deactivates_and_keeps_the_account(self):
        self.client.post(
            reverse("backoffice:person_toggle_active", args=[self.recent.pk]), secure=True
        )
        self.recent.refresh_from_db()
        self.assertFalse(self.recent.is_active)
        self.assertTrue(User.objects.filter(pk=self.recent.pk).exists())

    def test_putting_someone_back_leaves_their_password_working(self):
        self.client.post(
            reverse("backoffice:person_toggle_active", args=[self.deleted.pk]), secure=True
        )
        self.deleted.refresh_from_db()
        self.assertTrue(self.deleted.is_active)
        self.assertTrue(self.deleted.check_password("pw-1234512345"))

    def test_erase_for_good_removes_the_row(self):
        pk = self.deleted.pk
        self.client.post(reverse("backoffice:person_delete", args=[pk]), secure=True)
        self.assertFalse(User.objects.filter(pk=pk).exists())

    def test_staff_cannot_delete_themselves(self):
        self.client.post(
            reverse("backoffice:person_toggle_active", args=[self.staff.pk]), secure=True
        )
        self.staff.refresh_from_db()
        self.assertTrue(self.staff.is_active)

    def test_owners_cannot_see_the_list_at_all(self):
        self.client.force_login(self.recent)
        response = self.client.get(reverse("backoffice:people"), secure=True)
        self.assertEqual(response.status_code, 302)
