import pytest
from fastapi.testclient import TestClient

from src.main import app
from src.models.transform import TransformInfo, TransformsResponse

client = TestClient(app)

@pytest.fixture(autouse=True)
def setup_logging():
    """Setup logging for tests."""
    import logging
    logging.basicConfig(level=logging.DEBUG)


@pytest.mark.asyncio
async def test_list_transforms():
    """Test the list_transforms endpoint."""
    response = client.get("/list-transforms")

    assert response.status_code == 200
    data = response.json()

    # Validate response structure
    transforms = TransformsResponse(**data)
    assert isinstance(transforms.image_only, list)
    assert isinstance(transforms.dual, list)
    assert isinstance(transforms.transforms_3d, list)

    # Check for some common transforms that should be present

    image_only_transforms = [transform.name for transform in transforms.image_only]
    assert "AdditiveNoise" in image_only_transforms
    assert "RandomBrightnessContrast" in image_only_transforms
    assert "RandomShadow" in image_only_transforms
    assert "RandomRain" in image_only_transforms
    assert "RandomSnow" in image_only_transforms
    assert "RandomFog" in image_only_transforms
    assert "RandomSunFlare" in image_only_transforms

    dual_transforms = [transform.name for transform in transforms.dual]
    assert "HorizontalFlip" in dual_transforms
    assert "VerticalFlip" in dual_transforms
    assert "Affine" in dual_transforms

    transforms_3d = [transform.name for transform in transforms.transforms_3d]
    assert "CubicSymmetry" in transforms_3d
    assert "RandomCrop3D" in transforms_3d
    assert "CenterCrop3D" in transforms_3d


@pytest.mark.asyncio
async def test_get_transform_valid():
    """Test getting info for a valid transform."""
    response = client.get("/transform/Resize")

    if response.status_code != 200:
        print(f"Error response: {response.json()}")

    assert response.status_code == 200
    data = response.json()

    # Validate response structure
    transform_info = TransformInfo(**data)
    assert transform_info.name == "Resize"
    assert transform_info.targets == ["image", "mask", "bboxes", "keypoints", "volume", "mask3d"]


@pytest.mark.asyncio
async def test_get_transform_mosaic():
    """Test getting info for Mosaic transform."""
    response = client.get("/transform/Mosaic")

    if response.status_code != 200:
        print(f"Error response: {response.json()}")

    assert response.status_code == 200
    data = response.json()

    # Validate response structure
    transform_info = TransformInfo(**data)
    assert transform_info.name == "Mosaic"
    assert transform_info.targets == ["image", "mask", "bboxes", "keypoints"]


@pytest.mark.asyncio
async def test_get_transform_invalid():
    """Test getting info for an invalid transform."""
    response = client.get("/transform/NonExistentTransform")

    assert response.status_code == 404
    assert response.json()["detail"] == "Not found"


@pytest.mark.asyncio
async def test_transform_parameters():
    """Test that transform parameters are correctly described."""
    response = client.get("/transform/Resize")

    assert response.status_code == 200
    data = response.json()
    transform_info = TransformInfo(**data)

    # Check height parameter
    height_param = transform_info.fields["height"]
    assert height_param["type"] == "int"

    # Check width parameter
    width_param = transform_info.fields["width"]
    assert width_param["type"] == "int"


@pytest.mark.asyncio
async def test_list_transforms_categories():
    """Test that transform categories are properly separated."""
    response = client.get("/list-transforms")

    assert response.status_code == 200
    data = response.json()
    transforms = TransformsResponse(**data)

    # Get sets of transform names instead of TransformInfo objects
    image_only_names = {t.name for t in transforms.image_only}
    dual_names = {t.name for t in transforms.dual}
    transforms_3d_names = {t.name for t in transforms.transforms_3d}

    # Check that categories are mutually exclusive
    assert not image_only_names & dual_names
    assert not image_only_names & transforms_3d_names
    assert not dual_names & transforms_3d_names

    # Check that each category has at least some transforms
    assert len(transforms.image_only) > 0
    assert len(transforms.dual) >= 0  # Some implementations might not have dual transforms
    assert len(transforms.transforms_3d) >= 0


def test_transform_documentation():
    """Test that transform documentation is available."""
    response = client.get("/transform/Resize")

    assert response.status_code == 200
    data = response.json()
    transform_info = TransformInfo(**data)

    # Check that documentation exists
    assert transform_info.parsed_docstring is not None
    assert isinstance(transform_info.parsed_docstring, dict)
