"""Tests for ``dejavu.client.project.Project.update`` — focused on the
parameter-passthrough surface.

Verifies the kwarg → JSON payload mapping for every supported field
(``custom_instructions``, ``custom_categories``, ``retrieval_criteria``,
``multilingual``, ``decay``), the ValueError when no field is
provided, and the URL/method shape. The HTTP layer is mocked.
"""

from unittest.mock import MagicMock, patch

import pytest


@pytest.fixture
def project():
    """Build a ``Project`` with a mocked httpx client.

    Bypasses ``MemoryClient`` so the test stays focused on
    ``Project.update`` payload construction.
    """
    http = MagicMock()
    http.patch.return_value = MagicMock(
        json=lambda: {"message": "Updated"},
        raise_for_status=lambda: None,
    )
    with patch("dejavu.client.project.capture_client_event"):
        from dejavu.client.project import Project

        proj = Project(client=http, org_id="org1", project_id="proj1")
        yield proj, http


def _patch_payload(http):
    """Return the JSON body sent on the last PATCH, stripped of the SDK's
    standard auth params (``org_id``, ``project_id``) that ``_prepare_params``
    injects on every request."""
    assert http.patch.called, "expected a PATCH call"
    _, kwargs = http.patch.call_args
    body = dict(kwargs.get("json", {}))
    body.pop("org_id", None)
    body.pop("project_id", None)
    return body


class TestProjectUpdateDecay:
    def test_decay_true_sent_in_payload(self, project):
        proj, http = project
        proj.update(decay=True)
        assert _patch_payload(http) == {"decay": True}

    def test_decay_false_sent_in_payload(self, project):
        """Explicit ``False`` must round-trip — not be filtered as falsy."""
        proj, http = project
        proj.update(decay=False)
        assert _patch_payload(http) == {"decay": False}

    def test_decay_combined_with_multilingual(self, project):
        proj, http = project
        proj.update(multilingual=True, decay=True)
        assert _patch_payload(http) == {
            "multilingual": True,
            "decay": True,
        }

    def test_decay_omitted_when_none(self, project):
        """When the caller doesn't pass ``decay``, it must not appear in
        the payload — backwards compatible with pre-decay callers."""
        proj, http = project
        proj.update(multilingual=False)
        payload = _patch_payload(http)
        assert payload == {"multilingual": False}
        assert "decay" not in payload

    def test_no_args_raises_with_decay_in_message(self, project):
        proj, _ = project
        with pytest.raises(ValueError, match=r"decay"):
            proj.update()

    def test_url_targets_project_endpoint(self, project):
        proj, http = project
        proj.update(decay=True)
        args, _ = http.patch.call_args
        assert args[0] == "/api/v1/orgs/organizations/org1/projects/proj1/"


class TestProjectUpdateBackwardsCompat:
    def test_multilingual_only_still_works(self, project):
        """Pre-decay callers (multilingual only) keep working unchanged."""
        proj, http = project
        proj.update(multilingual=True)
        assert _patch_payload(http) == {"multilingual": True}

    def test_custom_instructions_only_still_works(self, project):
        proj, http = project
        proj.update(custom_instructions="be concise")
        assert _patch_payload(http) == {"custom_instructions": "be concise"}
