"""Tests for ilum.core.release — ReleaseManager plan/execute/rollback."""

from __future__ import annotations

from unittest.mock import MagicMock

import pytest

from ilum.config.manager import ConfigManager
from ilum.config.paths import IlumPaths
from ilum.core.helm import HelmClient, HelmResult
from ilum.core.kubernetes import KubeClient
from ilum.core.modules import ModuleResolver
from ilum.core.release import (
    ReleaseManager,
    ReleasePlan,
)
from ilum.core.safety import ValuesSnapshot, load_snapshot, save_snapshot
from ilum.errors import ReleaseExistsError, ReleaseNotFoundError


@pytest.fixture()
def release_mgr(tmp_config_dir: IlumPaths) -> ReleaseManager:
    """Provide a ReleaseManager with mocked clients."""
    helm = MagicMock(spec=HelmClient)
    helm.namespace = "default"
    helm._run.return_value = HelmResult(returncode=0, stdout="", stderr="", command=[])
    # Default: no releases exist
    helm.list_releases.return_value = HelmResult(
        returncode=0, stdout="", stderr="", json_data=[], command=[]
    )
    helm.get_values.return_value = HelmResult(
        returncode=0, stdout="", stderr="", json_data={}, command=[]
    )
    helm.get_values_all.return_value = HelmResult(
        returncode=0, stdout="", stderr="", json_data={}, command=[]
    )
    helm.install.return_value = HelmResult(returncode=0, stdout="deployed", stderr="", command=[])
    helm.upgrade.return_value = HelmResult(returncode=0, stdout="upgraded", stderr="", command=[])
    helm.uninstall.return_value = HelmResult(
        returncode=0, stdout="uninstalled", stderr="", command=[]
    )
    helm.rollback.return_value = HelmResult(
        returncode=0, stdout="rolled back", stderr="", command=[]
    )

    k8s = MagicMock(spec=KubeClient)
    resolver = ModuleResolver()
    config_mgr = ConfigManager(tmp_config_dir)
    config_mgr.ensure_config()

    return ReleaseManager(
        helm=helm,
        k8s=k8s,
        resolver=resolver,
        config_mgr=config_mgr,
        paths=tmp_config_dir,
    )


def _set_release_exists(mgr: ReleaseManager, name: str = "ilum") -> None:
    """Configure the mock so that ``release_exists`` returns True."""
    mgr.helm.list_releases.return_value = HelmResult(
        returncode=0,
        stdout="",
        stderr="",
        json_data=[{"name": name, "namespace": "default"}],
        command=[],
    )
    mgr.helm.history.return_value = HelmResult(
        returncode=0,
        stdout="",
        stderr="",
        json_data=[
            {
                "revision": 1,
                "status": "deployed",
                "chart": "ilum-6.7.0",
                "updated": "2024-01-15",
            }
        ],
        command=[],
    )


# ---------------------------------------------------------------------------
# ensure_repo
# ---------------------------------------------------------------------------


class TestEnsureRepo:
    def test_adds_repo_when_missing(self, release_mgr: ReleaseManager) -> None:
        from ilum.errors import HelmError

        release_mgr.helm._run.side_effect = HelmError("no repos")
        release_mgr.ensure_repo()
        release_mgr.helm.repo_add.assert_called_once()
        release_mgr.helm.repo_update.assert_called_once()

    def test_skips_when_present(self, release_mgr: ReleaseManager) -> None:
        release_mgr.helm._run.return_value = HelmResult(
            returncode=0,
            stdout="",
            stderr="",
            json_data=[{"name": "ilum", "url": "https://charts.ilum.cloud"}],
            command=[],
        )
        release_mgr.ensure_repo()
        release_mgr.helm.repo_add.assert_not_called()


# ---------------------------------------------------------------------------
# release_exists / get_release_info
# ---------------------------------------------------------------------------


class TestReleaseQueries:
    def test_release_exists_false(self, release_mgr: ReleaseManager) -> None:
        assert release_mgr.release_exists("ilum") is False

    def test_release_exists_true(self, release_mgr: ReleaseManager) -> None:
        _set_release_exists(release_mgr)
        assert release_mgr.release_exists("ilum") is True

    def test_get_release_info(self, release_mgr: ReleaseManager) -> None:
        _set_release_exists(release_mgr)
        info = release_mgr.get_release_info("ilum")
        assert info.name == "ilum"
        assert info.status == "deployed"
        assert info.chart_version == "6.7.0"
        assert info.revision == 1

    def test_get_release_info_rc_version(self, release_mgr: ReleaseManager) -> None:
        release_mgr.helm.list_releases.return_value = HelmResult(
            returncode=0,
            stdout="",
            stderr="",
            json_data=[{"name": "ilum", "namespace": "default"}],
            command=[],
        )
        release_mgr.helm.history.return_value = HelmResult(
            returncode=0,
            stdout="",
            stderr="",
            json_data=[
                {
                    "revision": 1,
                    "status": "deployed",
                    "chart": "ilum-6.7.0-RC1",
                    "updated": "2024-01-15",
                }
            ],
            command=[],
        )
        info = release_mgr.get_release_info("ilum")
        assert info.chart == "ilum"
        assert info.chart_version == "6.7.0-RC1"

    def test_get_release_info_not_found(self, release_mgr: ReleaseManager) -> None:
        from ilum.errors import HelmError

        release_mgr.helm.history.side_effect = HelmError("not found")
        with pytest.raises(ReleaseNotFoundError):
            release_mgr.get_release_info("nonexistent")

    def test_is_stuck_pending_upgrade(self, release_mgr: ReleaseManager) -> None:
        release_mgr.helm.list_releases.return_value = HelmResult(
            returncode=0,
            stdout="",
            stderr="",
            json_data=[{"name": "ilum"}],
            command=[],
        )
        release_mgr.helm.history.return_value = HelmResult(
            returncode=0,
            stdout="",
            stderr="",
            json_data=[
                {"revision": 2, "status": "pending-upgrade", "chart": "ilum-6.7.0", "updated": ""}
            ],
            command=[],
        )
        assert release_mgr.is_stuck("ilum") is True

    def test_is_stuck_deployed(self, release_mgr: ReleaseManager) -> None:
        _set_release_exists(release_mgr)
        assert release_mgr.is_stuck("ilum") is False


# ---------------------------------------------------------------------------
# plan_install
# ---------------------------------------------------------------------------


class TestPlanInstall:
    def test_basic_install_plan(self, release_mgr: ReleaseManager) -> None:
        plan = release_mgr.plan_install(
            release="ilum",
            chart="ilum/ilum",
            modules=["core", "ui"],
        )
        assert plan.action == "install"
        assert plan.release == "ilum"
        assert "ilum-core.enabled=true" in plan.set_flags
        assert "ilum-ui.enabled=true" in plan.set_flags

    def test_install_raises_when_exists(self, release_mgr: ReleaseManager) -> None:
        _set_release_exists(release_mgr)
        with pytest.raises(ReleaseExistsError):
            release_mgr.plan_install("ilum", "ilum/ilum", modules=["core"])

    def test_install_resolves_dependencies(self, release_mgr: ReleaseManager) -> None:
        plan = release_mgr.plan_install(
            release="ilum",
            chart="ilum/ilum",
            modules=["sql"],
        )
        # sql requires postgresql + core
        assert "postgresql.enabled=true" in plan.set_flags
        assert "ilum-core.enabled=true" in plan.set_flags

    def test_install_user_set_flags_appended_last(self, release_mgr: ReleaseManager) -> None:
        plan = release_mgr.plan_install(
            release="ilum",
            chart="ilum/ilum",
            modules=["core"],
            set_flags=["custom.key=value"],
        )
        # User flags should come after module flags
        core_idx = plan.set_flags.index("ilum-core.enabled=true")
        custom_idx = plan.set_flags.index("custom.key=value")
        assert custom_idx > core_idx

    def test_install_with_version(self, release_mgr: ReleaseManager) -> None:
        plan = release_mgr.plan_install(
            release="ilum",
            chart="ilum/ilum",
            modules=["core"],
            version="6.7.0",
        )
        assert plan.chart_version == "6.7.0"

    def test_install_validates_conflicts(self, release_mgr: ReleaseManager) -> None:
        plan = release_mgr.plan_install(
            release="ilum",
            chart="ilum/ilum",
            modules=["hive-metastore", "nessie"],
        )
        assert any("conflicts" in w for w in plan.warnings)


# ---------------------------------------------------------------------------
# plan_upgrade
# ---------------------------------------------------------------------------


class TestPlanUpgrade:
    def test_basic_upgrade_plan(self, release_mgr: ReleaseManager) -> None:
        _set_release_exists(release_mgr)
        plan = release_mgr.plan_upgrade(
            release="ilum",
            chart="ilum/ilum",
            set_flags=["ilum-core.replicas=3"],
        )
        assert plan.action == "upgrade"
        assert plan.effective_diff is not None

    def test_upgrade_raises_when_not_found(self, release_mgr: ReleaseManager) -> None:
        with pytest.raises(ReleaseNotFoundError):
            release_mgr.plan_upgrade("ilum", "ilum/ilum")

    def test_upgrade_detects_drift(self, release_mgr: ReleaseManager) -> None:
        _set_release_exists(release_mgr)
        # Save a snapshot, then return different live values
        snap = ValuesSnapshot(
            release="ilum",
            namespace="default",
            timestamp="",
            chart_version="6.7.0",
            values={"a": 1},
            operation="install",
        )
        save_snapshot(snap, release_mgr.paths.state_dir)

        release_mgr.helm.get_values.return_value = HelmResult(
            returncode=0,
            stdout="",
            stderr="",
            json_data={"a": 1, "external": "change"},
            command=[],
        )
        plan = release_mgr.plan_upgrade("ilum", "ilum/ilum")
        assert plan.drift is not None
        assert plan.drift.has_drift is True

    def test_upgrade_with_breaking_changes(self, release_mgr: ReleaseManager) -> None:
        _set_release_exists(release_mgr)
        # Current is 6.5.x, target is 6.6.x
        release_mgr.helm.history.return_value = HelmResult(
            returncode=0,
            stdout="",
            stderr="",
            json_data=[{"revision": 1, "status": "deployed", "chart": "ilum-6.5.0", "updated": ""}],
            command=[],
        )
        plan = release_mgr.plan_upgrade(
            "ilum",
            "ilum/ilum",
            version="6.6.0",
        )
        assert any("MongoDB" in w for w in plan.warnings)


# ---------------------------------------------------------------------------
# plan_enable / plan_disable
# ---------------------------------------------------------------------------


class TestPlanEnableDisable:
    def test_plan_enable_module(self, release_mgr: ReleaseManager) -> None:
        _set_release_exists(release_mgr)
        plan = release_mgr.plan_enable(
            release="ilum",
            chart="ilum/ilum",
            module_names=["sql"],
        )
        assert plan.action == "enable"
        assert "ilum-sql.enabled=true" in plan.set_flags
        assert plan.effective_diff is not None

    def test_plan_enable_detects_conflicts(self, release_mgr: ReleaseManager) -> None:
        """Enabling nessie when hive-metastore is live should produce conflict warnings."""
        _set_release_exists(release_mgr)
        # Simulate hive-metastore already enabled on the cluster
        release_mgr.helm.get_values.return_value = HelmResult(
            returncode=0,
            stdout="",
            stderr="",
            json_data={
                "ilum-hive-metastore": {"enabled": True},
                "ilum-core": {"enabled": True, "metastore": {"enabled": True, "type": "hive"}},
                "postgresql": {"enabled": True},
            },
            command=[],
        )
        release_mgr.helm.get_values_all = release_mgr.helm.get_values
        plan = release_mgr.plan_enable(
            release="ilum",
            chart="ilum/ilum",
            module_names=["nessie"],
        )
        assert any("conflicts" in w for w in plan.warnings)

    def test_plan_enable_after_connect_no_false_warnings(self, release_mgr: ReleaseManager) -> None:
        """After 'ilum connect', user-supplied values are empty but chart defaults
        enable core modules.  Enabling kafka (which requires core) must not produce
        false 'core is not enabled' warnings.

        Regression test for: module enable fails to detect default-enabled modules.
        """
        _set_release_exists(release_mgr)
        # User-supplied values are empty (typical after ``ilum connect``)
        release_mgr.helm.get_values.return_value = HelmResult(
            returncode=0, stdout="", stderr="", json_data={}, command=[]
        )
        # Computed values (user + chart defaults) show default modules as enabled
        release_mgr.helm.get_values_all.return_value = HelmResult(
            returncode=0,
            stdout="",
            stderr="",
            json_data={
                "ilum-core": {"enabled": True},
                "ilum-ui": {"enabled": True},
                "mongodb": {"enabled": True},
                "postgresql": {"enabled": True},
            },
            command=[],
        )
        plan = release_mgr.plan_enable(
            release="ilum",
            chart="ilum/ilum",
            module_names=["kafka"],
        )
        assert plan.action == "enable"
        # No false warnings about missing dependencies
        assert not plan.warnings

    def test_plan_disable_module(self, release_mgr: ReleaseManager) -> None:
        _set_release_exists(release_mgr)
        plan = release_mgr.plan_disable(
            release="ilum",
            chart="ilum/ilum",
            module_names=["jupyter"],
            active_modules=frozenset(["core", "ui", "jupyter", "mongodb"]),
        )
        assert plan.action == "disable"
        assert "ilum-jupyter.enabled=false" in plan.set_flags

    def test_disable_default_module_warns(self, release_mgr: ReleaseManager) -> None:
        _set_release_exists(release_mgr)
        plan = release_mgr.plan_disable(
            release="ilum",
            chart="ilum/ilum",
            module_names=["core"],
            active_modules=frozenset(["core", "ui"]),
        )
        assert any("default module" in w for w in plan.warnings)


# ---------------------------------------------------------------------------
# execute
# ---------------------------------------------------------------------------


class TestExecute:
    def test_execute_install(self, release_mgr: ReleaseManager) -> None:
        plan = release_mgr.plan_install(
            release="ilum",
            chart="ilum/ilum",
            modules=["core"],
        )
        result = release_mgr.execute(plan)
        release_mgr.helm.install.assert_called_once()
        assert result.returncode == 0
        # Verify snapshot was saved
        snap = load_snapshot("ilum", "default", release_mgr.paths.state_dir)
        assert snap is not None
        assert snap.operation == "install"

    def test_execute_upgrade(self, release_mgr: ReleaseManager) -> None:
        _set_release_exists(release_mgr)
        plan = release_mgr.plan_upgrade(
            release="ilum",
            chart="ilum/ilum",
            set_flags=["custom=true"],
        )
        result = release_mgr.execute(plan)
        release_mgr.helm.upgrade.assert_called_once()
        assert result.returncode == 0

    def test_execute_upgrade_uses_reuse_values(self, release_mgr: ReleaseManager) -> None:
        _set_release_exists(release_mgr)
        plan = release_mgr.plan_upgrade(
            release="ilum",
            chart="ilum/ilum",
            set_flags=["custom=true"],
        )
        release_mgr.execute(plan)
        call_kwargs = release_mgr.helm.upgrade.call_args
        assert call_kwargs.kwargs.get("reuse_values") is True

    def test_execute_enable_uses_reuse_values(self, release_mgr: ReleaseManager) -> None:
        _set_release_exists(release_mgr)
        plan = release_mgr.plan_enable(
            release="ilum",
            chart="ilum/ilum",
            module_names=["sql"],
        )
        release_mgr.execute(plan)
        call_kwargs = release_mgr.helm.upgrade.call_args
        assert call_kwargs.kwargs.get("reuse_values") is True

    def test_execute_upgrade_with_reset_defaults(self, release_mgr: ReleaseManager) -> None:
        _set_release_exists(release_mgr)
        plan = release_mgr.plan_upgrade(
            release="ilum",
            chart="ilum/ilum",
            set_flags=["custom=true"],
            reset_defaults=True,
        )
        release_mgr.execute(plan)
        call_kwargs = release_mgr.helm.upgrade.call_args
        assert call_kwargs.kwargs.get("reset_then_reuse_values") is True
        assert call_kwargs.kwargs.get("reuse_values") is False

    def test_preview_upgrade_with_reset_defaults(self, release_mgr: ReleaseManager) -> None:
        _set_release_exists(release_mgr)
        plan = release_mgr.plan_upgrade(
            release="ilum",
            chart="ilum/ilum",
            set_flags=["foo=bar"],
            reset_defaults=True,
        )
        release_mgr.helm.preview_upgrade.return_value = [
            "helm",
            "upgrade",
            "ilum",
            "ilum/ilum",
        ]
        release_mgr.preview_command(plan)
        call_kwargs = release_mgr.helm.preview_upgrade.call_args
        assert call_kwargs.kwargs.get("reset_then_reuse_values") is True
        assert call_kwargs.kwargs.get("reuse_values") is False

    def test_execute_uninstall(self, release_mgr: ReleaseManager) -> None:
        # Save a snapshot first
        snap = ValuesSnapshot(
            release="ilum",
            namespace="default",
            timestamp="",
            chart_version="6.7.0",
            values={},
            operation="install",
        )
        save_snapshot(snap, release_mgr.paths.state_dir)

        plan = ReleasePlan(
            action="uninstall",
            release="ilum",
            namespace="default",
            chart="",
        )
        release_mgr.execute(plan)
        release_mgr.helm.uninstall.assert_called_once_with(release="ilum")
        # Snapshot should be deleted
        assert load_snapshot("ilum", "default", release_mgr.paths.state_dir) is None

    def test_execute_unknown_action(self, release_mgr: ReleaseManager) -> None:
        plan = ReleasePlan(
            action="bogus",
            release="ilum",
            namespace="default",
            chart="",
        )
        with pytest.raises(ValueError, match="Unknown plan action"):
            release_mgr.execute(plan)


# ---------------------------------------------------------------------------
# rollback_if_stuck
# ---------------------------------------------------------------------------


class TestRollbackIfStuck:
    def test_rollback_when_stuck(self, release_mgr: ReleaseManager) -> None:
        release_mgr.helm.list_releases.return_value = HelmResult(
            returncode=0,
            stdout="",
            stderr="",
            json_data=[{"name": "ilum"}],
            command=[],
        )
        release_mgr.helm.history.return_value = HelmResult(
            returncode=0,
            stdout="",
            stderr="",
            json_data=[
                {"revision": 2, "status": "pending-upgrade", "chart": "ilum-6.7.0", "updated": ""}
            ],
            command=[],
        )
        assert release_mgr.rollback_if_stuck("ilum") is True
        release_mgr.helm.rollback.assert_called_once_with("ilum")

    def test_no_rollback_when_healthy(self, release_mgr: ReleaseManager) -> None:
        _set_release_exists(release_mgr)
        assert release_mgr.rollback_if_stuck("ilum") is False
        release_mgr.helm.rollback.assert_not_called()


# ---------------------------------------------------------------------------
# Config helpers
# ---------------------------------------------------------------------------


# ---------------------------------------------------------------------------
# fetch_computed_values
# ---------------------------------------------------------------------------


class TestFetchComputedValues:
    def test_fetch_computed_values(self, release_mgr: ReleaseManager) -> None:
        release_mgr.helm.get_values_all.return_value = HelmResult(
            returncode=0,
            stdout="",
            stderr="",
            json_data={"ilum-core": {"enabled": True}, "mongodb": {"enabled": True}},
            command=[],
        )
        result = release_mgr.fetch_computed_values("ilum")
        release_mgr.helm.get_values_all.assert_called_once_with("ilum")
        assert result == {"ilum-core": {"enabled": True}, "mongodb": {"enabled": True}}

    def test_fetch_computed_values_empty(self, release_mgr: ReleaseManager) -> None:
        release_mgr.helm.get_values_all.return_value = HelmResult(
            returncode=0,
            stdout="",
            stderr="",
            json_data=None,
            command=[],
        )
        result = release_mgr.fetch_computed_values("ilum")
        assert result == {}


# ---------------------------------------------------------------------------
# Config helpers
# ---------------------------------------------------------------------------


class TestConfigHelpers:
    def test_save_and_get_enabled_modules(self, release_mgr: ReleaseManager) -> None:
        release_mgr.save_enabled_modules(["core", "ui", "sql"])
        assert release_mgr.get_enabled_modules() == ["core", "ui", "sql"]

    def test_get_enabled_modules_empty(self, release_mgr: ReleaseManager) -> None:
        assert release_mgr.get_enabled_modules() == []

    def test_find_profile_for_release(self, release_mgr: ReleaseManager) -> None:
        config = release_mgr.config_mgr.load()
        config.profiles["default"].release_name = "ilum-prod"
        release_mgr.config_mgr.save(config)
        assert release_mgr._find_profile_for_release("ilum-prod") == "default"
        assert release_mgr._find_profile_for_release("nonexistent") is None

    def test_get_modules_by_release_name(self, release_mgr: ReleaseManager) -> None:
        config = release_mgr.config_mgr.load()
        config.profiles["default"].release_name = "ilum-prod"
        config.profiles["default"].enabled_modules = ["core", "sql"]
        release_mgr.config_mgr.save(config)
        assert release_mgr.get_enabled_modules(release="ilum-prod") == ["core", "sql"]


# ---------------------------------------------------------------------------
# preview_command
# ---------------------------------------------------------------------------


class TestPreviewCommand:
    def test_preview_install(self, release_mgr: ReleaseManager) -> None:
        plan = release_mgr.plan_install(release="ilum", chart="ilum/ilum", modules=["core"])
        release_mgr.helm.preview_install.return_value = [
            "helm",
            "install",
            "ilum",
            "ilum/ilum",
            "--atomic",
        ]
        cmd = release_mgr.preview_command(plan)
        release_mgr.helm.preview_install.assert_called_once()
        assert "helm" in cmd

    def test_preview_upgrade(self, release_mgr: ReleaseManager) -> None:
        _set_release_exists(release_mgr)
        plan = release_mgr.plan_upgrade(release="ilum", chart="ilum/ilum", set_flags=["foo=bar"])
        release_mgr.helm.preview_upgrade.return_value = ["helm", "upgrade", "ilum", "ilum/ilum"]
        cmd = release_mgr.preview_command(plan)
        release_mgr.helm.preview_upgrade.assert_called_once()
        assert "helm" in cmd
        call_kwargs = release_mgr.helm.preview_upgrade.call_args
        assert call_kwargs.kwargs.get("reuse_values") is True

    def test_preview_uninstall(self, release_mgr: ReleaseManager) -> None:
        plan = ReleasePlan(action="uninstall", release="ilum", namespace="default", chart="")
        release_mgr.helm.preview_uninstall.return_value = ["helm", "uninstall", "ilum"]
        cmd = release_mgr.preview_command(plan)
        release_mgr.helm.preview_uninstall.assert_called_once()
        assert "uninstall" in cmd

    def test_preview_enable(self, release_mgr: ReleaseManager) -> None:
        _set_release_exists(release_mgr)
        plan = release_mgr.plan_enable(release="ilum", chart="ilum/ilum", module_names=["sql"])
        release_mgr.helm.preview_upgrade.return_value = ["helm", "upgrade", "ilum", "ilum/ilum"]
        cmd = release_mgr.preview_command(plan)
        release_mgr.helm.preview_upgrade.assert_called_once()
        assert "helm" in cmd

    def test_preview_unknown_action_raises(self, release_mgr: ReleaseManager) -> None:
        plan = ReleasePlan(action="bogus", release="ilum", namespace="default", chart="")
        with pytest.raises(ValueError, match="Unknown plan action"):
            release_mgr.preview_command(plan)


# ---------------------------------------------------------------------------
# Breaking changes (rewritten with tuple comparison)
# ---------------------------------------------------------------------------


class TestBreakingChanges:
    def test_detects_65_to_66(self) -> None:
        warnings = ReleaseManager._check_breaking_changes("6.5.0", "6.6.0")
        assert any("MongoDB" in w for w in warnings)

    def test_detects_66_to_67(self) -> None:
        warnings = ReleaseManager._check_breaking_changes("6.6.0", "6.7.0")
        assert any("Langfuse" in w for w in warnings)

    def test_detects_both_65_to_67(self) -> None:
        warnings = ReleaseManager._check_breaking_changes("6.5.0", "6.7.0")
        assert any("MongoDB" in w for w in warnings)
        assert any("Langfuse" in w for w in warnings)

    def test_no_warnings_same_version(self) -> None:
        assert ReleaseManager._check_breaking_changes("6.7.0", "6.7.0") == []

    def test_no_warnings_downgrade(self) -> None:
        assert ReleaseManager._check_breaking_changes("6.7.0", "6.6.0") == []

    def test_no_warnings_unparseable(self) -> None:
        assert ReleaseManager._check_breaking_changes("garbage", "6.7.0") == []
        assert ReleaseManager._check_breaking_changes("6.7.0", "garbage") == []

    def test_minor_version_bump_notice(self) -> None:
        warnings = ReleaseManager._check_breaking_changes("6.7.0", "6.8.0")
        assert any("minor versions" in w for w in warnings)
        assert any("upgrade notes" in w.lower() for w in warnings)

    def test_patch_bump_no_notice(self) -> None:
        warnings = ReleaseManager._check_breaking_changes("6.7.0", "6.7.1")
        assert not any("minor versions" in w for w in warnings)

    def test_works_with_version_610(self) -> None:
        """Regression: string prefix '6.1' shouldn't match '6.10'."""
        # 6.10 should NOT trigger 6.5→6.6 or 6.6→6.7 breaking changes
        # unless we're actually crossing those ranges
        warnings = ReleaseManager._check_breaking_changes("6.9.0", "6.10.0")
        assert not any("MongoDB" in w for w in warnings)
        assert not any("Langfuse" in w for w in warnings)
        # But should still have minor bump notice
        assert any("minor versions" in w for w in warnings)
