"""Tests for cookie category, cookie, and allow-list schemas and routes."""

import uuid

import pytest
from pydantic import ValidationError

from src.schemas.cookie import (
    AllowListEntryCreate,
    AllowListEntryUpdate,
    CookieCategoryResponse,
    CookieCreate,
    CookieResponse,
    CookieUpdate,
    ReviewStatus,
    StorageType,
)

# ─── Schema tests ────────────────────────────────────────────────────


class TestStorageType:
    def test_values(self):
        assert StorageType.cookie == "cookie"
        assert StorageType.local_storage == "local_storage"
        assert StorageType.session_storage == "session_storage"
        assert StorageType.indexed_db == "indexed_db"


class TestReviewStatus:
    def test_values(self):
        assert ReviewStatus.pending == "pending"
        assert ReviewStatus.approved == "approved"
        assert ReviewStatus.rejected == "rejected"


class TestCookieCreate:
    def test_valid_minimal(self):
        schema = CookieCreate(name="_ga", domain=".example.com")
        assert schema.name == "_ga"
        assert schema.domain == ".example.com"
        assert schema.storage_type == StorageType.cookie
        assert schema.category_id is None

    def test_valid_full(self):
        cat_id = uuid.uuid4()
        schema = CookieCreate(
            name="_ga",
            domain=".google.com",
            storage_type=StorageType.cookie,
            category_id=cat_id,
            description="Google Analytics cookie",
            vendor="Google",
            path="/",
            max_age_seconds=63072000,
            is_http_only=False,
            is_secure=True,
            same_site="Lax",
        )
        assert schema.category_id == cat_id
        assert schema.max_age_seconds == 63072000

    def test_rejects_empty_name(self):
        with pytest.raises(ValidationError):
            CookieCreate(name="", domain=".example.com")

    def test_rejects_empty_domain(self):
        with pytest.raises(ValidationError):
            CookieCreate(name="_ga", domain="")


class TestCookieUpdate:
    def test_partial_update(self):
        schema = CookieUpdate(review_status=ReviewStatus.approved)
        dump = schema.model_dump(exclude_unset=True)
        assert dump == {"review_status": ReviewStatus.approved}

    def test_update_category(self):
        cat_id = uuid.uuid4()
        schema = CookieUpdate(category_id=cat_id)
        assert schema.category_id == cat_id


class TestAllowListEntryCreate:
    def test_valid(self):
        cat_id = uuid.uuid4()
        schema = AllowListEntryCreate(
            name_pattern="_ga*",
            domain_pattern=".google.com",
            category_id=cat_id,
            description="Google Analytics cookies",
        )
        assert schema.name_pattern == "_ga*"
        assert schema.category_id == cat_id

    def test_rejects_empty_name_pattern(self):
        with pytest.raises(ValidationError):
            AllowListEntryCreate(
                name_pattern="",
                domain_pattern=".example.com",
                category_id=uuid.uuid4(),
            )


class TestAllowListEntryUpdate:
    def test_partial_update(self):
        schema = AllowListEntryUpdate(description="Updated description")
        dump = schema.model_dump(exclude_unset=True)
        assert dump == {"description": "Updated description"}


class TestCookieCategoryResponse:
    def test_from_dict(self):
        now = "2024-01-01T00:00:00"
        resp = CookieCategoryResponse(
            id=uuid.uuid4(),
            name="Analytics",
            slug="analytics",
            description="Analytics cookies",
            is_essential=False,
            display_order=2,
            tcf_purpose_ids=[1, 3],
            gcm_consent_types=["analytics_storage"],
            created_at=now,
            updated_at=now,
        )
        assert resp.slug == "analytics"
        assert resp.is_essential is False


class TestCookieResponse:
    def test_from_dict(self):
        now = "2024-01-01T00:00:00"
        resp = CookieResponse(
            id=uuid.uuid4(),
            site_id=uuid.uuid4(),
            name="_ga",
            domain=".google.com",
            storage_type="cookie",
            review_status="pending",
            created_at=now,
            updated_at=now,
        )
        assert resp.name == "_ga"
        assert resp.review_status == "pending"


# ─── Route tests ─────────────────────────────────────────────────────


class TestCookieCategoryRoutes:
    def test_categories_route_registered(self, app):
        """Verify the categories routes are registered in the app."""
        routes = [r.path for r in app.routes]
        assert "/api/v1/cookies/categories" in routes
        assert "/api/v1/cookies/categories/{category_id}" in routes


class TestCookieRoutes:
    @pytest.mark.asyncio
    async def test_list_cookies_requires_auth(self, client):
        site_id = uuid.uuid4()
        resp = await client.get(f"/api/v1/cookies/sites/{site_id}")
        assert resp.status_code == 401

    @pytest.mark.asyncio
    async def test_create_cookie_requires_auth(self, client):
        site_id = uuid.uuid4()
        resp = await client.post(
            f"/api/v1/cookies/sites/{site_id}",
            json={"name": "_ga", "domain": ".google.com"},
        )
        assert resp.status_code == 401

    @pytest.mark.asyncio
    async def test_create_cookie_rejects_invalid_body(self, client):
        site_id = uuid.uuid4()
        resp = await client.post(
            f"/api/v1/cookies/sites/{site_id}",
            json={"name": "", "domain": ""},
            headers={"Authorization": "Bearer fake-token"},
        )
        # Should return 401 (bad token) or 422 (validation)
        assert resp.status_code in (401, 422)

    @pytest.mark.asyncio
    async def test_summary_route_requires_auth(self, client):
        site_id = uuid.uuid4()
        resp = await client.get(f"/api/v1/cookies/sites/{site_id}/summary")
        assert resp.status_code == 401


class TestAllowListRoutes:
    @pytest.mark.asyncio
    async def test_list_allow_list_requires_auth(self, client):
        site_id = uuid.uuid4()
        resp = await client.get(f"/api/v1/cookies/sites/{site_id}/allow-list")
        assert resp.status_code == 401

    @pytest.mark.asyncio
    async def test_create_allow_list_requires_auth(self, client):
        site_id = uuid.uuid4()
        resp = await client.post(
            f"/api/v1/cookies/sites/{site_id}/allow-list",
            json={
                "name_pattern": "_ga*",
                "domain_pattern": ".google.com",
                "category_id": str(uuid.uuid4()),
            },
        )
        assert resp.status_code == 401

    @pytest.mark.asyncio
    async def test_delete_allow_list_requires_auth(self, client):
        site_id = uuid.uuid4()
        entry_id = uuid.uuid4()
        resp = await client.delete(f"/api/v1/cookies/sites/{site_id}/allow-list/{entry_id}")
        assert resp.status_code == 401
