"""Tests for agent/onboarding.py — contextual first-touch hint helpers."""

from __future__ import annotations

import hermes_yaml as yaml

from agent.onboarding import (
    BUSY_INPUT_FLAG,
    TOOL_PROGRESS_FLAG,
    detect_openclaw_residue,
    is_seen,
    mark_seen,
)

class TestIsSeen:
    def test_empty_config_unseen(self):
        assert is_seen({}, BUSY_INPUT_FLAG) is False

    def test_seen_flag_true(self):
        cfg = {"onboarding": {"seen": {BUSY_INPUT_FLAG: True}}}
        assert is_seen(cfg, BUSY_INPUT_FLAG) is True

    def test_seen_flag_falsy(self):
        cfg = {"onboarding": {"seen": {BUSY_INPUT_FLAG: False}}}
        assert is_seen(cfg, BUSY_INPUT_FLAG) is False

class TestMarkSeen:

    def test_preserves_other_config(self, tmp_path):
        cfg_path = tmp_path / "config.yaml"
        cfg_path.write_text(yaml.safe_dump({
            "model": {"default": "claude-sonnet-4.6"},
            "display": {"skin": "default"},
        }))

        assert mark_seen(cfg_path, BUSY_INPUT_FLAG) is True
        loaded = yaml.safe_load(cfg_path.read_text())

        assert loaded["model"]["default"] == "claude-sonnet-4.6"
        assert loaded["display"]["skin"] == "default"
        assert loaded["onboarding"]["seen"][BUSY_INPUT_FLAG] is True

    def test_idempotent(self, tmp_path):
        cfg_path = tmp_path / "config.yaml"
        mark_seen(cfg_path, BUSY_INPUT_FLAG)
        first = cfg_path.read_text()

        # Second call must be a no-op on-disk content (file may be touched,
        # but the YAML contents should be identical).
        mark_seen(cfg_path, BUSY_INPUT_FLAG)
        second = cfg_path.read_text()

        assert yaml.safe_load(first) == yaml.safe_load(second)

class TestRoundTrip:
    """After mark_seen, is_seen on the re-loaded config must return True."""

    def test_mark_then_is_seen(self, tmp_path):
        cfg_path = tmp_path / "config.yaml"

        assert mark_seen(cfg_path, BUSY_INPUT_FLAG) is True
        loaded = yaml.safe_load(cfg_path.read_text())

        assert is_seen(loaded, BUSY_INPUT_FLAG) is True
        assert is_seen(loaded, TOOL_PROGRESS_FLAG) is False

    def test_mark_both_flags_independently(self, tmp_path):
        cfg_path = tmp_path / "config.yaml"

        mark_seen(cfg_path, BUSY_INPUT_FLAG)
        mark_seen(cfg_path, TOOL_PROGRESS_FLAG)
        loaded = yaml.safe_load(cfg_path.read_text())

        assert is_seen(loaded, BUSY_INPUT_FLAG) is True
        assert is_seen(loaded, TOOL_PROGRESS_FLAG) is True

# ---------------------------------------------------------------------------
# OpenClaw residue banner
# ---------------------------------------------------------------------------

class TestDetectOpenclawResidue:
    def test_returns_true_when_openclaw_dir_present(self, tmp_path):
        (tmp_path / ".openclaw").mkdir()
        assert detect_openclaw_residue(home=tmp_path) is True

    def test_returns_false_when_path_is_a_file(self, tmp_path):
        # A stray file named ``.openclaw`` is NOT a workspace — skip the banner.
        (tmp_path / ".openclaw").write_text("oops")
        assert detect_openclaw_residue(home=tmp_path) is False

class TestProfileBuildMode:

    def test_non_mapping_config_safe(self):
        from agent.onboarding import profile_build_mode

        assert profile_build_mode("not a dict") == "ask"  # type: ignore[arg-type]
        assert profile_build_mode({"onboarding": "nope"}) == "ask"


class TestFirstContactTurnNote:
    def test_returns_profile_directive_and_marks_seen(self, tmp_path):
        from agent.onboarding import (
            PROFILE_BUILD_FLAG,
            first_contact_turn_note,
            profile_build_directive,
        )

        cfg_path = tmp_path / "config.yaml"
        cfg = {"onboarding": {"profile_build": "ask"}}
        note = first_contact_turn_note(
            cfg,
            cfg_path,
            session_history_empty=True,
            install_has_prior_sessions=False,
        )
        assert note == profile_build_directive().strip()
        loaded = yaml.safe_load(cfg_path.read_text())
        assert loaded["onboarding"]["seen"][PROFILE_BUILD_FLAG] is True

    def test_every_first_contact_note_puts_a_real_task_first(self, tmp_path):
        # Default "ask" (profile-build offer) and "off" (plain intro) must both
        # tell the model to do a first-message task before the intro/offer.
        from agent.onboarding import TASK_FIRST_CLAUSE, first_contact_turn_note

        for mode in ("ask", "off"):
            note = first_contact_turn_note(
                {"onboarding": {"profile_build": mode}},
                tmp_path / f"{mode}.yaml",
                session_history_empty=True,
                install_has_prior_sessions=False,
            )
            assert TASK_FIRST_CLAUSE in note, mode

    def test_returns_none_when_not_first_contact(self, tmp_path):
        from agent.onboarding import first_contact_turn_note

        cfg_path = tmp_path / "config.yaml"
        assert (
            first_contact_turn_note(
                {},
                cfg_path,
                session_history_empty=False,
                install_has_prior_sessions=False,
            )
            is None
        )
        assert (
            first_contact_turn_note(
                {},
                cfg_path,
                session_history_empty=True,
                install_has_prior_sessions=True,
            )
            is None
        )
        assert not cfg_path.exists()
