"""E2E: Output target lifecycle.

Tests target CRUD with a dependency on a device:
create device -> create target -> list -> update -> delete target -> cleanup device.
"""



class TestOutputTargetLifecycle:
    """A user wires up an output target to a device."""

    def _create_device(self, client) -> str:
        """Helper: create a mock device and return its ID."""
        resp = client.post("/api/v1/devices", json={
            "name": "Target Test Device",
            "url": "mock://target-test",
            "device_type": "mock",
            "led_count": 60,
        })
        assert resp.status_code == 201
        return resp.json()["id"]

    def test_full_target_crud_lifecycle(self, client):
        device_id = self._create_device(client)

        # 1. List targets -- should be empty
        resp = client.get("/api/v1/output-targets")
        assert resp.status_code == 200
        assert resp.json()["count"] == 0

        # 2. Create an output target referencing the device
        create_payload = {
            "name": "E2E Test Target",
            "target_type": "led",
            "device_id": device_id,
            "fps": 30,
            "protocol": "ddp",
            "tags": ["e2e"],
        }
        resp = client.post("/api/v1/output-targets", json=create_payload)
        assert resp.status_code == 201, f"Create failed: {resp.text}"
        target = resp.json()
        target_id = target["id"]
        assert target["name"] == "E2E Test Target"
        assert target["device_id"] == device_id
        assert target["target_type"] == "led"
        assert target["fps"] == 30
        assert target["protocol"] == "ddp"

        # 3. List targets -- should contain the new target
        resp = client.get("/api/v1/output-targets")
        assert resp.status_code == 200
        data = resp.json()
        assert data["count"] == 1
        assert data["targets"][0]["id"] == target_id

        # 4. Get target by ID
        resp = client.get(f"/api/v1/output-targets/{target_id}")
        assert resp.status_code == 200
        assert resp.json()["name"] == "E2E Test Target"

        # 5. Update the target -- change name and fps
        resp = client.put(
            f"/api/v1/output-targets/{target_id}",
            json={"name": "Updated Target", "fps": 60},
        )
        assert resp.status_code == 200
        updated = resp.json()
        assert updated["name"] == "Updated Target"
        assert updated["fps"] == 60

        # 6. Verify update via GET
        resp = client.get(f"/api/v1/output-targets/{target_id}")
        assert resp.status_code == 200
        assert resp.json()["name"] == "Updated Target"

        # 7. Delete the target
        resp = client.delete(f"/api/v1/output-targets/{target_id}")
        assert resp.status_code == 204

        # 8. Verify target is gone
        resp = client.get(f"/api/v1/output-targets/{target_id}")
        assert resp.status_code == 404

        # 9. Clean up the device
        resp = client.delete(f"/api/v1/devices/{device_id}")
        assert resp.status_code == 204

    def test_cannot_delete_device_referenced_by_target(self, client):
        """Deleting a device that has a target should return 409."""
        device_id = self._create_device(client)

        resp = client.post("/api/v1/output-targets", json={
            "name": "Blocking Target",
            "target_type": "led",
            "device_id": device_id,
        })
        assert resp.status_code == 201
        target_id = resp.json()["id"]

        # Attempt to delete device -- should fail
        resp = client.delete(f"/api/v1/devices/{device_id}")
        assert resp.status_code == 409
        assert "referenced" in resp.json()["detail"].lower()

        # Clean up: delete target first, then device
        resp = client.delete(f"/api/v1/output-targets/{target_id}")
        assert resp.status_code == 204
        resp = client.delete(f"/api/v1/devices/{device_id}")
        assert resp.status_code == 204

    def test_create_target_with_invalid_device_returns_422(self, client):
        """Creating a target with a non-existent device_id returns 422."""
        resp = client.post("/api/v1/output-targets", json={
            "name": "Orphan Target",
            "target_type": "led",
            "device_id": "nonexistent_device",
        })
        assert resp.status_code == 422

    def test_get_nonexistent_target_returns_404(self, client):
        resp = client.get("/api/v1/output-targets/nonexistent_id")
        assert resp.status_code == 404
