"""
Tests for Themis views — health checks, profile settings, API key CRUD.
"""
from django.contrib.auth import get_user_model
from django.test import Client, TestCase
from django.urls import reverse

from themis.encryption import decrypt_value, encrypt_value
from themis.models import UserAPIKey

User = get_user_model()


class HealthCheckViewTest(TestCase):
    """Tests for readiness and liveness probe endpoints."""

    def test_live_returns_200(self):
        """Liveness endpoint returns 200 with status alive."""
        response = self.client.get(reverse("themis:live"))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json(), {"status": "alive"})

    def test_ready_returns_200(self):
        """Readiness endpoint returns 200 when DB is available."""
        response = self.client.get(reverse("themis:ready"))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json()["status"], "ready")

    def test_health_endpoints_reject_post(self):
        """Health endpoints only accept GET."""
        response = self.client.post(reverse("themis:live"))
        self.assertEqual(response.status_code, 405)
        response = self.client.post(reverse("themis:ready"))
        self.assertEqual(response.status_code, 405)

    def test_health_endpoints_no_auth_required(self):
        """Health endpoints are accessible without authentication."""
        client = Client()  # No login
        self.assertEqual(client.get(reverse("themis:live")).status_code, 200)
        self.assertEqual(client.get(reverse("themis:ready")).status_code, 200)


class ProfileSettingsViewTest(TestCase):
    """Tests for the profile settings view."""

    def setUp(self):
        self.user = User.objects.create_user(username="viewuser", password="pass123")
        self.client.login(username="viewuser", password="pass123")
        self.url = reverse("themis:profile-settings")

    def test_get_settings_page(self):
        """GET returns 200 with the settings form."""
        response = self.client.get(self.url)
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "form")
        self.assertTemplateUsed(response, "themis/profile/settings.html")

    def test_post_valid_settings(self):
        """POST with valid data saves and redirects."""
        response = self.client.post(
            self.url,
            data={
                "home_timezone": "America/Toronto",
                "current_timezone": "",
                "date_format": "DD/MM/YYYY",
                "time_format": "12-hour",
                "thousand_separator": "period",
                "week_start": "sunday",
                "theme_mode": "dark",
                "theme_name": "dracula",
                "dark_theme_name": "night",
                "notifications_enabled": True,
                "notifications_min_level": "info",
                "notification_retention_days": 30,
            },
        )
        self.assertRedirects(response, self.url)
        self.user.profile.refresh_from_db()
        self.assertEqual(self.user.profile.home_timezone, "America/Toronto")
        self.assertEqual(self.user.profile.date_format, "DD/MM/YYYY")

    def test_post_invalid_settings(self):
        """POST with invalid data re-renders form with errors."""
        response = self.client.post(
            self.url,
            data={
                "home_timezone": "Invalid/TZ",
                "current_timezone": "",
                "date_format": "YYYY-MM-DD",
                "time_format": "24-hour",
                "thousand_separator": "comma",
                "week_start": "monday",
                "theme_mode": "auto",
                "theme_name": "corporate",
                "dark_theme_name": "business",
                "notifications_enabled": True,
                "notifications_min_level": "info",
                "notification_retention_days": 30,
            },
        )
        self.assertEqual(response.status_code, 200)
        form = response.context["form"]
        self.assertFalse(form.is_valid())
        self.assertIn("home_timezone", form.errors)

    def test_login_required(self):
        """Unauthenticated users are redirected to login."""
        self.client.logout()
        response = self.client.get(self.url)
        self.assertEqual(response.status_code, 302)
        self.assertIn("login", response.url)


class KeyListViewTest(TestCase):
    """Tests for the API key list view."""

    def setUp(self):
        self.user = User.objects.create_user(username="listuser", password="pass123")
        self.other_user = User.objects.create_user(username="other", password="pass123")
        self.client.login(username="listuser", password="pass123")
        self.url = reverse("themis:key-list")

        self.key1 = UserAPIKey.objects.create(
            user=self.user,
            service_name="OpenAI",
            key_type="api",
            encrypted_value=encrypt_value("sk-test1"),
        )
        self.key2 = UserAPIKey.objects.create(
            user=self.user,
            service_name="Anthropic",
            key_type="api",
            encrypted_value=encrypt_value("sk-test2"),
        )
        self.other_key = UserAPIKey.objects.create(
            user=self.other_user,
            service_name="Secret",
            key_type="api",
            encrypted_value=encrypt_value("sk-other"),
        )

    def test_get_key_list(self):
        """GET returns 200 with user's keys."""
        response = self.client.get(self.url)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, "themis/keys/list.html")
        keys = response.context["keys"]
        self.assertEqual(keys.count(), 2)

    def test_only_own_keys(self):
        """User only sees their own keys, not other users'."""
        response = self.client.get(self.url)
        keys = response.context["keys"]
        key_ids = [k.pk for k in keys]
        self.assertIn(self.key1.pk, key_ids)
        self.assertNotIn(self.other_key.pk, key_ids)

    def test_login_required(self):
        """Unauthenticated users are redirected."""
        self.client.logout()
        response = self.client.get(self.url)
        self.assertEqual(response.status_code, 302)

    def test_rejects_post(self):
        """Key list only accepts GET."""
        response = self.client.post(self.url)
        self.assertEqual(response.status_code, 405)


class KeyCreateViewTest(TestCase):
    """Tests for the API key create view."""

    def setUp(self):
        self.user = User.objects.create_user(username="createuser", password="pass123")
        self.client.login(username="createuser", password="pass123")
        self.url = reverse("themis:key-create")

    def test_get_create_form(self):
        """GET returns 200 with the create form."""
        response = self.client.get(self.url)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, "themis/keys/create.html")

    def test_post_creates_key(self):
        """POST with valid data creates a key and redirects."""
        response = self.client.post(
            self.url,
            data={
                "service_name": "OpenAI",
                "key_type": "api",
                "label": "Work",
                "key_value": "sk-abc123456789",
                "instructions": "Get from dashboard",
                "help_url": "https://platform.openai.com",
            },
        )
        self.assertRedirects(response, reverse("themis:key-list"))
        self.assertEqual(UserAPIKey.objects.filter(user=self.user).count(), 1)
        key = UserAPIKey.objects.get(user=self.user)
        self.assertEqual(key.service_name, "OpenAI")
        # Verify the value was encrypted
        self.assertEqual(decrypt_value(key.encrypted_value), "sk-abc123456789")

    def test_post_invalid_data(self):
        """POST with missing fields re-renders form."""
        response = self.client.post(
            self.url,
            data={
                "service_name": "",
                "key_type": "api",
                "key_value": "sk-test",
            },
        )
        self.assertEqual(response.status_code, 200)
        self.assertEqual(UserAPIKey.objects.filter(user=self.user).count(), 0)

    def test_login_required(self):
        """Unauthenticated users are redirected."""
        self.client.logout()
        response = self.client.get(self.url)
        self.assertEqual(response.status_code, 302)


class KeyDetailViewTest(TestCase):
    """Tests for the API key detail view."""

    def setUp(self):
        self.user = User.objects.create_user(username="detailuser", password="pass123")
        self.other_user = User.objects.create_user(username="otherdetail", password="pass123")
        self.client.login(username="detailuser", password="pass123")
        self.key = UserAPIKey.objects.create(
            user=self.user,
            service_name="OpenAI",
            key_type="api",
            encrypted_value=encrypt_value("sk-detail-test"),
        )
        self.other_key = UserAPIKey.objects.create(
            user=self.other_user,
            service_name="Other",
            key_type="api",
            encrypted_value=encrypt_value("sk-other"),
        )

    def test_get_detail(self):
        """GET returns 200 with key details."""
        url = reverse("themis:key-detail", kwargs={"pk": self.key.pk})
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, "themis/keys/detail.html")
        self.assertEqual(response.context["key"], self.key)

    def test_cannot_view_other_users_key(self):
        """Cannot view another user's key — returns 404."""
        url = reverse("themis:key-detail", kwargs={"pk": self.other_key.pk})
        response = self.client.get(url)
        self.assertEqual(response.status_code, 404)

    def test_nonexistent_key_404(self):
        """Non-existent UUID returns 404."""
        import uuid

        url = reverse("themis:key-detail", kwargs={"pk": uuid.uuid4()})
        response = self.client.get(url)
        self.assertEqual(response.status_code, 404)


class KeyEditViewTest(TestCase):
    """Tests for the API key edit view."""

    def setUp(self):
        self.user = User.objects.create_user(username="editviewuser", password="pass123")
        self.client.login(username="editviewuser", password="pass123")
        self.key = UserAPIKey.objects.create(
            user=self.user,
            service_name="OpenAI",
            key_type="api",
            label="Original",
            encrypted_value=encrypt_value("sk-edit-test"),
        )
        self.url = reverse("themis:key-edit", kwargs={"pk": self.key.pk})

    def test_get_edit_form(self):
        """GET returns 200 with the edit form."""
        response = self.client.get(self.url)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, "themis/keys/edit.html")

    def test_post_updates_key(self):
        """POST with valid data updates metadata and redirects."""
        response = self.client.post(
            self.url,
            data={
                "service_name": "Anthropic",
                "key_type": "token",
                "label": "Updated Label",
                "instructions": "New instructions",
                "help_url": "",
                "is_active": True,
            },
        )
        self.assertRedirects(
            response,
            reverse("themis:key-detail", kwargs={"pk": self.key.pk}),
        )
        self.key.refresh_from_db()
        self.assertEqual(self.key.service_name, "Anthropic")
        self.assertEqual(self.key.label, "Updated Label")
        # Encrypted value unchanged
        self.assertEqual(decrypt_value(self.key.encrypted_value), "sk-edit-test")

    def test_cannot_edit_other_users_key(self):
        """Cannot edit another user's key — returns 404."""
        other = User.objects.create_user(username="otheredit", password="pass123")
        other_key = UserAPIKey.objects.create(
            user=other,
            service_name="Other",
            key_type="api",
            encrypted_value=encrypt_value("sk-nope"),
        )
        url = reverse("themis:key-edit", kwargs={"pk": other_key.pk})
        response = self.client.get(url)
        self.assertEqual(response.status_code, 404)


class KeyDeleteViewTest(TestCase):
    """Tests for the API key delete view."""

    def setUp(self):
        self.user = User.objects.create_user(username="deluser", password="pass123")
        self.client.login(username="deluser", password="pass123")
        self.key = UserAPIKey.objects.create(
            user=self.user,
            service_name="ToDelete",
            key_type="api",
            encrypted_value=encrypt_value("sk-delete"),
        )
        self.url = reverse("themis:key-delete", kwargs={"pk": self.key.pk})

    def test_post_deletes_key(self):
        """POST deletes the key and redirects to list."""
        response = self.client.post(self.url)
        self.assertRedirects(response, reverse("themis:key-list"))
        self.assertFalse(UserAPIKey.objects.filter(pk=self.key.pk).exists())

    def test_get_not_allowed(self):
        """GET is not allowed on delete endpoint."""
        response = self.client.get(self.url)
        self.assertEqual(response.status_code, 405)

    def test_cannot_delete_other_users_key(self):
        """Cannot delete another user's key — returns 404."""
        other = User.objects.create_user(username="otherdel", password="pass123")
        other_key = UserAPIKey.objects.create(
            user=other,
            service_name="Other",
            key_type="api",
            encrypted_value=encrypt_value("sk-nope"),
        )
        url = reverse("themis:key-delete", kwargs={"pk": other_key.pk})
        response = self.client.post(url)
        self.assertEqual(response.status_code, 404)

    def test_login_required(self):
        """Unauthenticated users are redirected."""
        self.client.logout()
        response = self.client.post(self.url)
        self.assertEqual(response.status_code, 302)
