"""Tests for S3 PutBucketTagging / GetBucketTagging / DeleteBucketTagging operations."""

from __future__ import annotations

from pathlib import Path

import httpx
import pytest

from lws.providers.s3.provider import S3Provider
from lws.providers.s3.routes import create_s3_app


@pytest.fixture
async def provider(tmp_path: Path):
    p = S3Provider(data_dir=tmp_path)
    await p.start()
    yield p
    await p.stop()


@pytest.fixture
def client(provider: S3Provider) -> httpx.AsyncClient:
    app = create_s3_app(provider)
    transport = httpx.ASGITransport(app=app)
    return httpx.AsyncClient(transport=transport, base_url="http://testserver")


class TestBucketTagging:
    @pytest.mark.asyncio
    async def test_put_and_get_bucket_tagging(
        self, client: httpx.AsyncClient, provider: S3Provider
    ) -> None:
        # Arrange
        bucket_name = "my-bucket"
        await provider.create_bucket(bucket_name)
        expected_put_status = 204
        expected_get_status = 200

        tagging_xml = (
            '<?xml version="1.0" encoding="UTF-8"?>'
            "<Tagging>"
            "<TagSet>"
            "<Tag><Key>env</Key><Value>production</Value></Tag>"
            "<Tag><Key>team</Key><Value>platform</Value></Tag>"
            "</TagSet>"
            "</Tagging>"
        )

        # Act
        put_resp = await client.put(
            f"/{bucket_name}?tagging",
            content=tagging_xml.encode(),
            headers={"content-type": "application/xml"},
        )
        get_resp = await client.get(f"/{bucket_name}?tagging")

        # Assert
        assert put_resp.status_code == expected_put_status
        assert get_resp.status_code == expected_get_status
        assert "<Tagging>" in get_resp.text
        assert "<Key>env</Key>" in get_resp.text
        assert "<Value>production</Value>" in get_resp.text
        assert "<Key>team</Key>" in get_resp.text
        assert "<Value>platform</Value>" in get_resp.text

    @pytest.mark.asyncio
    async def test_get_bucket_tagging_empty(
        self, client: httpx.AsyncClient, provider: S3Provider
    ) -> None:
        # Arrange
        await provider.create_bucket("my-bucket")
        expected_status = 200

        # Act
        resp = await client.get("/my-bucket?tagging")

        # Assert
        assert resp.status_code == expected_status
        assert "<Tagging>" in resp.text
        assert "<TagSet>" in resp.text

    @pytest.mark.asyncio
    async def test_delete_bucket_tagging(
        self, client: httpx.AsyncClient, provider: S3Provider
    ) -> None:
        # Arrange
        bucket_name = "my-bucket"
        await provider.create_bucket(bucket_name)
        expected_delete_status = 204
        expected_get_status = 200

        tagging_xml = (
            "<Tagging><TagSet><Tag><Key>env</Key><Value>staging</Value></Tag></TagSet></Tagging>"
        )
        await client.put(
            f"/{bucket_name}?tagging",
            content=tagging_xml.encode(),
            headers={"content-type": "application/xml"},
        )

        # Act
        delete_resp = await client.delete(f"/{bucket_name}?tagging")

        # Assert
        assert delete_resp.status_code == expected_delete_status
        get_resp = await client.get(f"/{bucket_name}?tagging")
        assert get_resp.status_code == expected_get_status
        assert "<Tag>" not in get_resp.text

    @pytest.mark.asyncio
    async def test_put_bucket_tagging_no_such_bucket(self, client: httpx.AsyncClient) -> None:
        # Act
        tagging_xml = (
            "<Tagging><TagSet><Tag><Key>env</Key><Value>dev</Value></Tag></TagSet></Tagging>"
        )
        resp = await client.put(
            "/nonexistent-bucket?tagging",
            content=tagging_xml.encode(),
            headers={"content-type": "application/xml"},
        )

        # Assert
        expected_status = 404
        assert resp.status_code == expected_status
        assert "NoSuchBucket" in resp.text

    @pytest.mark.asyncio
    async def test_delete_bucket_tagging_no_such_bucket(self, client: httpx.AsyncClient) -> None:
        # Act
        resp = await client.delete("/nonexistent-bucket?tagging")

        # Assert
        expected_status = 404
        assert resp.status_code == expected_status
        assert "NoSuchBucket" in resp.text

    @pytest.mark.asyncio
    async def test_put_bucket_tagging_malformed_xml(
        self, client: httpx.AsyncClient, provider: S3Provider
    ) -> None:
        # Arrange
        await provider.create_bucket("my-bucket")

        # Act
        resp = await client.put(
            "/my-bucket?tagging",
            content=b"not valid xml",
            headers={"content-type": "application/xml"},
        )

        # Assert
        expected_status = 400
        assert resp.status_code == expected_status
        assert "MalformedXML" in resp.text
