"""Tests for catalog API endpoints"""

import pytest
from .conftest import Client, State
from .api import create_namespace, create_collection, create_itemType


# Test data constants
NAMESPACE_CATALOG = "CatalogTestNamespace"
COLLECTION_CATALOG_01 = "CatalogCollection01"
COLLECTION_CATALOG_02 = "CatalogCollection02"
ITEMTYPE_CATALOG_01 = "CatalogItemType01"
ITEMTYPE_CATALOG_02 = "CatalogItemType02"
ITEMTYPE_CATALOG_03 = "CatalogItemType03"


@pytest.fixture(scope="module")
def catalog_test_data(client: Client, state: State):
    """Setup test data for catalog tests"""
    # Create namespace
    namespace_id = create_namespace(client, NAMESPACE_CATALOG)

    # Create collections
    collection_id_01 = create_collection(client, COLLECTION_CATALOG_01, namespace_id)
    collection_id_02 = create_collection(client, COLLECTION_CATALOG_02, namespace_id)

    # Create item types
    itemtype_id_01 = create_itemType(client, ITEMTYPE_CATALOG_01, collection_id_01)
    itemtype_id_02 = create_itemType(client, ITEMTYPE_CATALOG_02, collection_id_01)
    itemtype_id_03 = create_itemType(client, ITEMTYPE_CATALOG_03, collection_id_02)

    return {
        "namespace_id": namespace_id,
        "namespace_name": NAMESPACE_CATALOG,
        "collections": {
            COLLECTION_CATALOG_01: collection_id_01,
            COLLECTION_CATALOG_02: collection_id_02,
        },
        "item_types": {
            ITEMTYPE_CATALOG_01: itemtype_id_01,
            ITEMTYPE_CATALOG_02: itemtype_id_02,
            ITEMTYPE_CATALOG_03: itemtype_id_03,
        },
    }


def test_item_type_by_path_full_path(client: Client, catalog_test_data: dict):
    """Test getting item type ID by full path (namespace/collection/itemType)"""
    path = f"{NAMESPACE_CATALOG}/{COLLECTION_CATALOG_01}/{ITEMTYPE_CATALOG_01}"
    response = client.get(f"/v1/catalog/item-types/path/{path}")

    assert response.status_code == 200, response.text
    result = response.json()

    # Verify the response structure
    assert "itemTypeId" in result
    assert "path" in result

    # Verify the returned UUID matches the expected item type
    assert result["itemTypeId"] == str(
        catalog_test_data["item_types"][ITEMTYPE_CATALOG_01]
    )
    assert result["path"] == path.lower()


def test_item_type_by_path_different_item_type(client: Client, catalog_test_data: dict):
    """Test getting a different item type in the same collection"""
    path = f"{NAMESPACE_CATALOG}/{COLLECTION_CATALOG_01}/{ITEMTYPE_CATALOG_02}"
    response = client.get(f"/v1/catalog/item-types/path/{path}")

    assert response.status_code == 200, response.text
    result = response.json()

    assert result["itemTypeId"] == str(
        catalog_test_data["item_types"][ITEMTYPE_CATALOG_02]
    )
    assert result["path"] == path.lower()


def test_item_type_by_path_different_collection(
    client: Client, catalog_test_data: dict
):
    """Test getting item type from a different collection"""
    path = f"{NAMESPACE_CATALOG}/{COLLECTION_CATALOG_02}/{ITEMTYPE_CATALOG_03}"
    response = client.get(f"/v1/catalog/item-types/path/{path}")

    assert response.status_code == 200, response.text
    result = response.json()

    assert result["itemTypeId"] == str(
        catalog_test_data["item_types"][ITEMTYPE_CATALOG_03]
    )
    assert result["path"] == path.lower()


def test_item_type_by_path_partial_path_error(client: Client, catalog_test_data: dict):
    """Test that partial path (namespace/collection) without item type returns error"""
    path = f"{NAMESPACE_CATALOG}/{COLLECTION_CATALOG_01}"
    response = client.get(f"/v1/catalog/item-types/path/{path}")

    assert response.status_code == 400, response.text
    error_data = response.json()
    assert (
        "at least namespace and collection" in error_data["detail"]["message"].lower()
    )


def test_item_type_by_path_with_leading_slash(client: Client, catalog_test_data: dict):
    """Test that leading slashes are handled correctly"""
    path = f"/{NAMESPACE_CATALOG}/{COLLECTION_CATALOG_01}/{ITEMTYPE_CATALOG_01}"
    response = client.get(f"/v1/catalog/item-types/path/{path}")

    assert response.status_code == 200, response.text
    result = response.json()

    assert result["itemTypeId"] == str(
        catalog_test_data["item_types"][ITEMTYPE_CATALOG_01]
    )
    # Path should be lowercased and cleaned (leading slash removed)
    assert result["path"] == path.lower()


def test_item_type_by_path_with_trailing_slash(client: Client, catalog_test_data: dict):
    """Test that trailing slashes are handled correctly"""
    path = f"{NAMESPACE_CATALOG}/{COLLECTION_CATALOG_01}/{ITEMTYPE_CATALOG_01}/"
    response = client.get(f"/v1/catalog/item-types/path/{path}")

    assert response.status_code == 200, response.text
    result = response.json()

    assert result["itemTypeId"] == str(
        catalog_test_data["item_types"][ITEMTYPE_CATALOG_01]
    )
    # Path should be lowercased and cleaned (trailing slash removed)
    assert result["path"] == path.lower()


def test_item_type_by_path_not_found_namespace(client: Client, catalog_test_data: dict):
    """Test error when namespace doesn't exist"""
    path = "NonExistentNamespace/SomeCollection/SomeItemType"
    response = client.get(f"/v1/catalog/item-types/path/{path}")

    assert response.status_code == 404, response.text
    error_data = response.json()
    assert "not found" in error_data["detail"]["message"].lower()


def test_item_type_by_path_not_found_collection(
    client: Client, catalog_test_data: dict
):
    """Test error when collection doesn't exist"""
    path = f"{NAMESPACE_CATALOG}/NonExistentCollection/SomeItemType"
    response = client.get(f"/v1/catalog/item-types/path/{path}")

    assert response.status_code == 404, response.text
    error_data = response.json()
    assert "not found" in error_data["detail"]["message"].lower()


def test_item_type_by_path_not_found_item_type(client: Client, catalog_test_data: dict):
    """Test error when item type doesn't exist"""
    path = f"{NAMESPACE_CATALOG}/{COLLECTION_CATALOG_01}/NonExistentItemType"
    response = client.get(f"/v1/catalog/item-types/path/{path}")

    assert response.status_code == 404, response.text
    error_data = response.json()
    assert "not found" in error_data["detail"]["message"].lower()


def test_item_type_by_path_invalid_too_short(client: Client, catalog_test_data: dict):
    """Test error when path has insufficient parts (requires 3 parts: namespace/collection/itemType)"""
    path = "OnlyNamespace"
    response = client.get(f"/v1/catalog/item-types/path/{path}")

    assert response.status_code == 400, response.text
    error_data = response.json()
    assert (
        "at least namespace and collection" in error_data["detail"]["message"].lower()
    )


def test_item_type_by_path_invalid_two_parts(client: Client, catalog_test_data: dict):
    """Test error when path has only two parts (namespace/collection)"""
    path = f"{NAMESPACE_CATALOG}/{COLLECTION_CATALOG_01}"
    response = client.get(f"/v1/catalog/item-types/path/{path}")

    assert response.status_code == 400, response.text
    error_data = response.json()
    assert (
        "at least namespace and collection" in error_data["detail"]["message"].lower()
    )


def test_item_type_by_path_empty(client: Client, catalog_test_data: dict):
    """Test error when path is empty"""
    path = ""
    response = client.get(f"/v1/catalog/item-types/path/{path}")

    # FastAPI should handle this as a 404 or 400
    assert response.status_code in [400, 404, 422], response.text


def test_item_type_by_path_only_slashes(client: Client, catalog_test_data: dict):
    """Test error when path contains only slashes"""
    path = "///"
    response = client.get(f"/v1/catalog/item-types/path/{path}")

    assert response.status_code == 400, response.text
    error_data = response.json()
    assert (
        "at least namespace and collection" in error_data["detail"]["message"].lower()
    )


def test_item_type_by_path_case_insensitive(client: Client, catalog_test_data: dict):
    """Test that path matching is case-insensitive"""
    # Use lowercase version of all path components
    path = f"{NAMESPACE_CATALOG.lower()}/{COLLECTION_CATALOG_01.lower()}/{ITEMTYPE_CATALOG_01.lower()}"
    response = client.get(f"/v1/catalog/item-types/path/{path}")

    assert response.status_code == 200, response.text
    result = response.json()

    # Should match and return the correct item type regardless of case
    assert result["itemTypeId"] == str(
        catalog_test_data["item_types"][ITEMTYPE_CATALOG_01]
    )
    assert result["path"] == path.lower()


def test_item_type_by_path_mixed_case(client: Client, catalog_test_data: dict):
    """Test that path matching works with mixed case"""
    # Use uppercase for all parts
    namespace = NAMESPACE_CATALOG.upper()
    collection = COLLECTION_CATALOG_01.upper()
    item_type = ITEMTYPE_CATALOG_01.upper()

    path = f"{namespace}/{collection}/{item_type}"
    response = client.get(f"/v1/catalog/item-types/path/{path}")

    assert response.status_code == 200, response.text
    result = response.json()

    assert result["itemTypeId"] == str(
        catalog_test_data["item_types"][ITEMTYPE_CATALOG_01]
    )
    # Path should be returned in lowercase
    assert result["path"] == path.lower()


def test_item_type_by_path_url_encoded(client: Client, catalog_test_data: dict):
    """Test that URL-encoded paths work correctly"""
    import urllib.parse

    path = f"{NAMESPACE_CATALOG}/{COLLECTION_CATALOG_01}/{ITEMTYPE_CATALOG_01}"
    encoded_path = urllib.parse.quote(path)

    response = client.get(f"/v1/catalog/item-types/path/{encoded_path}")

    assert response.status_code == 200, response.text
    result = response.json()

    assert result["itemTypeId"] == str(
        catalog_test_data["item_types"][ITEMTYPE_CATALOG_01]
    )
    # Path should be decoded and lowercased
    assert result["path"] == path.lower()
