"""
Tests for Collection CRUD API endpoints.

Tests the following endpoints:
- GET /library/api/collections
- POST /library/api/collections
- PUT /library/api/collections/<id>
- DELETE /library/api/collections/<id>
"""

import uuid


# Import helpers from conftest
from .conftest import delete_test_collection


class TestGetCollections:
    """Tests for GET /library/api/collections endpoint."""

    def test_get_collections_unauthenticated(self, client):
        """Unauthenticated request is rejected."""
        response = client.get("/library/api/collections")
        # Should redirect to login or return 401
        assert response.status_code in [302, 401]

    def test_get_collections_authenticated_empty(self, authenticated_client):
        """Returns collections list (may include default Library)."""
        response = authenticated_client.get("/library/api/collections")
        assert response.status_code == 200

        data = response.get_json()
        assert data["success"] is True
        assert "collections" in data
        assert isinstance(data["collections"], list)

    def test_get_collections_with_data(
        self, authenticated_client, create_collection_helper
    ):
        """Returns created collections."""
        # Create a test collection
        created = create_collection_helper(
            name="API Test Collection",
            description="Testing GET endpoint",
        )
        assert created is not None

        response = authenticated_client.get("/library/api/collections")
        assert response.status_code == 200

        data = response.get_json()
        assert data["success"] is True

        # Find our created collection
        collection_names = [c["name"] for c in data["collections"]]
        assert "API Test Collection" in collection_names

    def test_get_collections_includes_metadata(
        self, authenticated_client, create_collection_helper
    ):
        """Collections include required metadata fields."""
        created = create_collection_helper()
        assert created is not None

        response = authenticated_client.get("/library/api/collections")
        assert response.status_code == 200

        data = response.get_json()
        assert len(data["collections"]) > 0

        # Check metadata fields
        coll = data["collections"][0]
        assert "id" in coll
        assert "name" in coll
        assert "description" in coll
        assert "created_at" in coll
        assert "collection_type" in coll
        assert "document_count" in coll


class TestCreateCollection:
    """Tests for POST /library/api/collections endpoint."""

    def test_create_collection_unauthenticated(self, client):
        """Unauthenticated request is rejected."""
        response = client.post(
            "/library/api/collections",
            json={"name": "Test", "description": "Test"},
            content_type="application/json",
        )
        assert response.status_code in [302, 401]

    def test_create_collection_success(self, authenticated_client):
        """Successfully creates a new collection."""
        unique_name = f"Test Collection {uuid.uuid4().hex[:8]}"

        response = authenticated_client.post(
            "/library/api/collections",
            json={
                "name": unique_name,
                "description": "A test collection",
                "type": "user_uploads",
            },
            content_type="application/json",
        )

        assert response.status_code == 200

        data = response.get_json()
        assert data["success"] is True
        assert data["collection"]["name"] == unique_name
        assert data["collection"]["description"] == "A test collection"
        assert "id" in data["collection"]

        # Cleanup
        delete_test_collection(authenticated_client, data["collection"]["id"])

    def test_create_collection_defaults_private(self, authenticated_client):
        """A new collection with no is_public flag defaults to private."""
        name = f"Priv {uuid.uuid4().hex[:8]}"
        resp = authenticated_client.post(
            "/library/api/collections",
            json={"name": name},
            content_type="application/json",
        )
        assert resp.status_code == 200
        coll = resp.get_json()["collection"]
        assert coll["is_public"] is False
        delete_test_collection(authenticated_client, coll["id"])

    def test_create_and_toggle_collection_is_public(self, authenticated_client):
        """is_public can be set at create and flipped via PUT, and is
        reflected in the list API."""
        name = f"Pub {uuid.uuid4().hex[:8]}"
        resp = authenticated_client.post(
            "/library/api/collections",
            json={"name": name, "is_public": True},
            content_type="application/json",
        )
        assert resp.status_code == 200
        coll = resp.get_json()["collection"]
        cid = coll["id"]
        assert coll["is_public"] is True

        # List reflects it
        listing = authenticated_client.get(
            "/library/api/collections"
        ).get_json()["collections"]
        match = next(c for c in listing if c["id"] == cid)
        assert match["is_public"] is True

        # The collection-details load path (documents endpoint) also exposes
        # is_public so the details-page toggle can reflect current state.
        docs = authenticated_client.get(
            f"/library/api/collections/{cid}/documents"
        )
        assert docs.status_code == 200
        assert docs.get_json()["collection"]["is_public"] is True

        # Flip back to private via PUT
        put = authenticated_client.put(
            f"/library/api/collections/{cid}",
            json={"is_public": False},
            content_type="application/json",
        )
        assert put.status_code == 200
        assert put.get_json()["collection"]["is_public"] is False

        delete_test_collection(authenticated_client, cid)

    def test_create_collection_empty_name(self, authenticated_client):
        """Rejects collection with empty name."""
        response = authenticated_client.post(
            "/library/api/collections",
            json={"name": "", "description": "No name"},
            content_type="application/json",
        )

        assert response.status_code == 400

        data = response.get_json()
        assert data["success"] is False
        assert (
            "required" in data["error"].lower()
            or "name" in data["error"].lower()
        )

    def test_create_collection_whitespace_name(self, authenticated_client):
        """Rejects collection with whitespace-only name."""
        response = authenticated_client.post(
            "/library/api/collections",
            json={"name": "   ", "description": "Whitespace name"},
            content_type="application/json",
        )

        assert response.status_code == 400

    def test_create_collection_duplicate_name(self, authenticated_client):
        """Rejects collection with duplicate name."""
        unique_name = f"Duplicate Test {uuid.uuid4().hex[:8]}"

        # Create first collection
        response1 = authenticated_client.post(
            "/library/api/collections",
            json={"name": unique_name, "description": "First"},
            content_type="application/json",
        )
        assert response1.status_code == 200
        collection_id = response1.get_json()["collection"]["id"]

        try:
            # Try to create duplicate
            response2 = authenticated_client.post(
                "/library/api/collections",
                json={"name": unique_name, "description": "Duplicate"},
                content_type="application/json",
            )

            assert response2.status_code == 400

            data = response2.get_json()
            assert data["success"] is False
            assert "exists" in data["error"].lower()
        finally:
            # Cleanup
            delete_test_collection(authenticated_client, collection_id)

    def test_create_collection_without_description(self, authenticated_client):
        """Creates collection without description."""
        unique_name = f"No Desc Collection {uuid.uuid4().hex[:8]}"

        response = authenticated_client.post(
            "/library/api/collections",
            json={"name": unique_name},
            content_type="application/json",
        )

        assert response.status_code == 200

        data = response.get_json()
        assert data["success"] is True
        assert data["collection"]["name"] == unique_name

        # Cleanup
        delete_test_collection(authenticated_client, data["collection"]["id"])


class TestUpdateCollection:
    """Tests for PUT /library/api/collections/<id> endpoint."""

    def test_update_collection_unauthenticated(self, client):
        """Unauthenticated request is rejected."""
        response = client.put(
            "/library/api/collections/some-id",
            json={"name": "Updated"},
            content_type="application/json",
        )
        assert response.status_code in [302, 401]

    def test_update_collection_name(
        self, authenticated_client, create_collection_helper
    ):
        """Successfully updates collection name."""
        created = create_collection_helper(name="Original Name")
        assert created is not None

        new_name = f"Updated Name {uuid.uuid4().hex[:8]}"
        response = authenticated_client.put(
            f"/library/api/collections/{created['id']}",
            json={"name": new_name},
            content_type="application/json",
        )

        assert response.status_code == 200

        data = response.get_json()
        assert data["success"] is True
        assert data["collection"]["name"] == new_name

    def test_update_collection_description(
        self, authenticated_client, create_collection_helper
    ):
        """Successfully updates collection description."""
        created = create_collection_helper(description="Original description")
        assert created is not None

        response = authenticated_client.put(
            f"/library/api/collections/{created['id']}",
            json={"description": "Updated description"},
            content_type="application/json",
        )

        assert response.status_code == 200

        data = response.get_json()
        assert data["success"] is True
        assert data["collection"]["description"] == "Updated description"

    def test_update_collection_not_found(self, authenticated_client):
        """Returns 404 for non-existent collection."""
        fake_id = str(uuid.uuid4())
        response = authenticated_client.put(
            f"/library/api/collections/{fake_id}",
            json={"name": "Updated"},
            content_type="application/json",
        )

        assert response.status_code == 404

        data = response.get_json()
        assert data["success"] is False
        assert "not found" in data["error"].lower()

    def test_update_collection_duplicate_name(
        self, authenticated_client, create_collection_helper
    ):
        """Rejects update with duplicate name."""
        # Create two collections
        coll1 = create_collection_helper(
            name=f"Collection A {uuid.uuid4().hex[:8]}"
        )
        coll2 = create_collection_helper(
            name=f"Collection B {uuid.uuid4().hex[:8]}"
        )
        assert coll1 is not None and coll2 is not None

        # Try to rename coll2 to coll1's name
        response = authenticated_client.put(
            f"/library/api/collections/{coll2['id']}",
            json={"name": coll1["name"]},
            content_type="application/json",
        )

        assert response.status_code == 400

        data = response.get_json()
        assert data["success"] is False
        assert "exists" in data["error"].lower()


class TestDeleteCollection:
    """Tests for DELETE /library/api/collections/<id> endpoint."""

    def test_delete_collection_unauthenticated(self, client):
        """Unauthenticated request is rejected."""
        response = client.delete("/library/api/collections/some-id")
        assert response.status_code in [302, 401]

    def test_delete_collection_success(self, authenticated_client):
        """Successfully deletes a collection."""
        # Create a collection to delete
        unique_name = f"To Delete {uuid.uuid4().hex[:8]}"
        create_response = authenticated_client.post(
            "/library/api/collections",
            json={"name": unique_name, "description": "Will be deleted"},
            content_type="application/json",
        )
        assert create_response.status_code == 200
        collection_id = create_response.get_json()["collection"]["id"]

        # Delete it
        response = authenticated_client.delete(
            f"/library/api/collections/{collection_id}"
        )
        assert response.status_code == 200

        data = response.get_json()
        assert data["success"] is True

        # Verify it's gone
        list_response = authenticated_client.get("/library/api/collections")
        collections = list_response.get_json()["collections"]
        collection_ids = [c["id"] for c in collections]
        assert collection_id not in collection_ids

    def test_delete_collection_not_found(self, authenticated_client):
        """Returns 404 for non-existent collection."""
        fake_id = str(uuid.uuid4())
        response = authenticated_client.delete(
            f"/library/api/collections/{fake_id}"
        )

        assert response.status_code == 404

        data = response.get_json()
        assert data["success"] is False
        assert "not found" in data["error"].lower()


class TestCollectionIntegration:
    """Integration tests for collection workflow."""

    def test_create_read_update_delete_flow(self, authenticated_client):
        """Full CRUD workflow."""
        unique_name = f"CRUD Test {uuid.uuid4().hex[:8]}"

        # Create
        create_response = authenticated_client.post(
            "/library/api/collections",
            json={"name": unique_name, "description": "Initial"},
            content_type="application/json",
        )
        assert create_response.status_code == 200
        collection_id = create_response.get_json()["collection"]["id"]

        try:
            # Read
            list_response = authenticated_client.get("/library/api/collections")
            assert list_response.status_code == 200
            collections = list_response.get_json()["collections"]
            our_coll = next(
                (c for c in collections if c["id"] == collection_id), None
            )
            assert our_coll is not None
            assert our_coll["name"] == unique_name

            # Update
            updated_name = f"Updated {uuid.uuid4().hex[:8]}"
            update_response = authenticated_client.put(
                f"/library/api/collections/{collection_id}",
                json={"name": updated_name, "description": "Updated desc"},
                content_type="application/json",
            )
            assert update_response.status_code == 200

            # Verify update
            list_response2 = authenticated_client.get(
                "/library/api/collections"
            )
            collections2 = list_response2.get_json()["collections"]
            our_coll2 = next(
                (c for c in collections2 if c["id"] == collection_id), None
            )
            assert our_coll2["name"] == updated_name
            assert our_coll2["description"] == "Updated desc"

        finally:
            # Delete
            delete_response = authenticated_client.delete(
                f"/library/api/collections/{collection_id}"
            )
            assert delete_response.status_code == 200
