from django.test import TestCase


class CorsPreflightTests(TestCase):
    def test_browser_may_send_organization_header(self):
        """The SPA sends X-Organization on every call; a preflight that rejects it breaks the whole app."""
        response = self.client.options(
            "/api/v1/me/",
            HTTP_ORIGIN="http://localhost:5170",
            HTTP_ACCESS_CONTROL_REQUEST_METHOD="GET",
            HTTP_ACCESS_CONTROL_REQUEST_HEADERS="authorization,x-organization",
        )
        allowed = response["access-control-allow-headers"].lower()
        self.assertIn("x-organization", allowed)
        self.assertIn("authorization", allowed)


class ProductionDomainsTests(TestCase):
    """Frontend https://noffice.ir talks to https://api.noffice.ir: the browser's preflight and the real response must both allow it."""

    ORIGIN = "https://noffice.ir"
    PRODUCTION = {
        "CORS_ALLOWED_ORIGINS": ["https://noffice.ir", "https://www.noffice.ir"],
        "ALLOWED_HOSTS": ["api.noffice.ir"],
    }

    def preflight(self, method, path="/api/v1/members/1/", origin=None):
        return self.client.options(
            path,
            HTTP_HOST="api.noffice.ir",
            HTTP_ORIGIN=origin or self.ORIGIN,
            HTTP_ACCESS_CONTROL_REQUEST_METHOD=method,
            HTTP_ACCESS_CONTROL_REQUEST_HEADERS="authorization,content-type,x-organization",
        )

    def test_every_method_the_app_uses_is_allowed_from_the_frontend_domain(self):
        with self.settings(**self.PRODUCTION):
            for method in ("GET", "POST", "PUT", "PATCH", "DELETE"):
                response = self.preflight(method)
                self.assertEqual(response.status_code, 200, method)
                self.assertEqual(response["access-control-allow-origin"], self.ORIGIN)
                self.assertIn(method, response["access-control-allow-methods"])
                headers = response["access-control-allow-headers"].lower()
                for needed in ("authorization", "content-type", "x-organization"):
                    self.assertIn(needed, headers)

    def test_www_domain_is_allowed_too(self):
        with self.settings(**self.PRODUCTION):
            response = self.preflight("GET", origin="https://www.noffice.ir")
            self.assertEqual(response["access-control-allow-origin"], "https://www.noffice.ir")

    def test_actual_response_carries_the_cors_header_even_when_it_is_an_error(self):
        """A 401 without the header would reach the SPA as an opaque network error instead of 'please sign in'."""
        with self.settings(**self.PRODUCTION):
            for path in ("/api/v1/me/", "/api/v1/auth/login/", "/api/auth/refresh/"):
                response = self.client.post(path, HTTP_HOST="api.noffice.ir", HTTP_ORIGIN=self.ORIGIN)
                self.assertIn(response.status_code, (400, 401, 405), path)
                self.assertEqual(response["access-control-allow-origin"], self.ORIGIN, path)

    def test_other_websites_are_not_allowed(self):
        with self.settings(**self.PRODUCTION):
            response = self.preflight("GET", origin="https://evil.example")
            self.assertNotIn("access-control-allow-origin", response)
            response = self.client.get("/api/v1/me/", HTTP_HOST="api.noffice.ir", HTTP_ORIGIN="https://noffice.ir.evil.example")
            self.assertNotIn("access-control-allow-origin", response)
