"""Tests for webhook endpoint handlers."""

import hmac
import json

import pytest
from fastapi.testclient import TestClient


class TestWebhookEndpoint:
    """Test suite for /webhook/gitea endpoint."""

    def _create_signature(self, payload: dict[str, object], secret: str) -> str:
        """Create HMAC SHA256 signature for payload."""
        # Use separators to match FastAPI's JSON encoding (no spaces)
        payload_bytes = json.dumps(payload, separators=(',', ':')).encode("utf-8")
        return hmac.new(secret.encode("utf-8"), payload_bytes, "sha256").hexdigest()

    def test_webhook_missing_signature(
        self, client: TestClient, sample_assigned_payload: dict[str, object]
    ) -> None:
        """Test that webhook without signature returns 401."""
        response = client.post("/webhook/gitea", json=sample_assigned_payload)
        assert response.status_code == 401
        assert "Invalid or missing signature" in response.json()["detail"]

    def test_webhook_invalid_signature(
        self, client: TestClient, sample_assigned_payload: dict[str, object]
    ) -> None:
        """Test that webhook with invalid signature returns 401."""
        headers = {"X-Gitea-Signature": "invalid_signature"}
        response = client.post(
            "/webhook/gitea", json=sample_assigned_payload, headers=headers
        )
        assert response.status_code == 401
        assert "Invalid or missing signature" in response.json()["detail"]

    def test_webhook_assigned_event(
        self,
        client: TestClient,
        sample_assigned_payload: dict[str, object],
        webhook_secret: str,
    ) -> None:
        """Test that assigned event is processed successfully."""
        signature = self._create_signature(sample_assigned_payload, webhook_secret)
        headers = {"X-Gitea-Signature": signature}

        response = client.post(
            "/webhook/gitea", json=sample_assigned_payload, headers=headers
        )

        assert response.status_code == 200
        assert response.json()["status"] == "success"
        assert response.json()["action"] == "assigned"
        assert response.json()["issue_number"] == 157

    def test_webhook_unassigned_event(
        self,
        client: TestClient,
        sample_unassigned_payload: dict[str, object],
        webhook_secret: str,
    ) -> None:
        """Test that unassigned event is processed successfully."""
        signature = self._create_signature(sample_unassigned_payload, webhook_secret)
        headers = {"X-Gitea-Signature": signature}

        response = client.post(
            "/webhook/gitea", json=sample_unassigned_payload, headers=headers
        )

        assert response.status_code == 200
        assert response.json()["status"] == "success"
        assert response.json()["action"] == "unassigned"
        assert response.json()["issue_number"] == 157

    def test_webhook_closed_event(
        self,
        client: TestClient,
        sample_closed_payload: dict[str, object],
        webhook_secret: str,
    ) -> None:
        """Test that closed event is processed successfully."""
        signature = self._create_signature(sample_closed_payload, webhook_secret)
        headers = {"X-Gitea-Signature": signature}

        response = client.post(
            "/webhook/gitea", json=sample_closed_payload, headers=headers
        )

        assert response.status_code == 200
        assert response.json()["status"] == "success"
        assert response.json()["action"] == "closed"
        assert response.json()["issue_number"] == 157

    def test_webhook_unsupported_action(
        self, client: TestClient, webhook_secret: str
    ) -> None:
        """Test that unsupported actions are handled gracefully."""
        payload = {
            "action": "opened",  # Not a supported action
            "number": 157,
            "issue": {"id": 157, "number": 157, "title": "Test"},
        }
        signature = self._create_signature(payload, webhook_secret)
        headers = {"X-Gitea-Signature": signature}

        response = client.post("/webhook/gitea", json=payload, headers=headers)

        assert response.status_code == 200
        assert response.json()["status"] == "ignored"
        assert response.json()["action"] == "opened"

    def test_webhook_malformed_payload(
        self, client: TestClient, webhook_secret: str
    ) -> None:
        """Test that malformed payload returns 422."""
        payload = {"invalid": "payload"}  # Missing required fields
        signature = self._create_signature(payload, webhook_secret)
        headers = {"X-Gitea-Signature": signature}

        response = client.post("/webhook/gitea", json=payload, headers=headers)

        assert response.status_code == 422

    def test_webhook_logs_events(
        self,
        client: TestClient,
        sample_assigned_payload: dict[str, object],
        webhook_secret: str,
        caplog: pytest.LogCaptureFixture,
    ) -> None:
        """Test that webhook events are logged."""
        signature = self._create_signature(sample_assigned_payload, webhook_secret)
        headers = {"X-Gitea-Signature": signature}

        with caplog.at_level("INFO"):
            response = client.post(
                "/webhook/gitea", json=sample_assigned_payload, headers=headers
            )

        assert response.status_code == 200
        # Check that event was logged
        assert any("Webhook event received" in record.message for record in caplog.records)
        assert any("action=assigned" in record.message for record in caplog.records)
        assert any("issue_number=157" in record.message for record in caplog.records)


class TestWebhookRateLimiting:
    """Test suite for webhook rate limiting."""

    def test_webhook_has_rate_limit_configured(self) -> None:
        """Test that webhook endpoint has rate limiting configured."""
        from src.webhook import handle_gitea_webhook

        # Verify the rate limit decorator is applied
        # slowapi adds __wrapped__ attribute to decorated functions
        assert hasattr(handle_gitea_webhook, "__wrapped__") or hasattr(
            handle_gitea_webhook, "__name__"
        )

        # Verify the endpoint is the webhook handler
        assert handle_gitea_webhook.__name__ == "handle_gitea_webhook"


class TestHealthEndpoint:
    """Test suite for /health endpoint."""

    def test_health_check_returns_200(self, client: TestClient) -> None:
        """Test that health check endpoint returns 200 OK."""
        response = client.get("/health")
        assert response.status_code == 200
        assert response.json()["status"] == "healthy"

    def test_health_check_includes_service_name(self, client: TestClient) -> None:
        """Test that health check includes service name."""
        response = client.get("/health")
        assert response.status_code == 200
        assert "service" in response.json()
        assert response.json()["service"] == "mosaic-coordinator"
