from click.testing import CliRunner

from neurovault.cli import main
from neurovault.engine import NeurovaultEngine


def test_cli_graph_and_audit(monkeypatch, tmp_path):
    vault = NeurovaultEngine.init("test", no_embedding=True, base_dir=str(tmp_path))
    vault.ingest("Alex uses Python", source="user")

    import neurovault.cli as cli_module

    monkeypatch.setattr(cli_module, "_get_vault", lambda name="default": vault)

    runner = CliRunner()
    graph = runner.invoke(main, ["graph", "Alex", "--format", "json"])
    assert graph.exit_code == 0

    audit = runner.invoke(main, ["audit", "--format", "json"])
    assert audit.exit_code == 0
    assert "active_memories" in audit.output

    decay = runner.invoke(main, ["decay", "--limit", "5"])
    assert decay.exit_code == 0

    decay_run = runner.invoke(main, ["decay", "--run", "--limit", "5"])
    assert decay_run.exit_code == 0

    plugins = runner.invoke(main, ["plugin", "list"])
    assert plugins.exit_code == 0

    plugin_enable = runner.invoke(main, ["plugin", "enable", "demo-plugin"])
    assert plugin_enable.exit_code == 0

    plugin_config = runner.invoke(main, ["plugin", "config", "demo-plugin", "--set", "token=abc"])
    assert plugin_config.exit_code == 0

    plugin_health = runner.invoke(main, ["plugin", "health", "demo-plugin"])
    assert plugin_health.exit_code == 0

    events = runner.invoke(main, ["event", "list", "--format", "json", "--limit", "5"])
    assert events.exit_code == 0

    graph_rebuild = runner.invoke(main, ["chronos-graph", "rebuild"])
    assert graph_rebuild.exit_code == 0

    graph_neighbors = runner.invoke(main, ["chronos-graph", "neighbors", "Alex", "--format", "json"])
    assert graph_neighbors.exit_code == 0

    graph_path = runner.invoke(main, ["chronos-graph", "path", "Alex", "Python", "--format", "json"])
    assert graph_path.exit_code == 0

    persona_list = runner.invoke(main, ["persona", "list"])
    assert persona_list.exit_code == 0

    persona_create = runner.invoke(main, ["persona", "create", "work"])
    assert persona_create.exit_code == 0

    persona_use = runner.invoke(main, ["persona", "use", "work"])
    assert persona_use.exit_code == 0
    vault.ingest("Work milestone due Friday", source="user")

    back_to_default = runner.invoke(main, ["persona", "use", "default"])
    assert back_to_default.exit_code == 0

    merge = runner.invoke(main, ["merge", "work", "--strategy", "additive", "--dry-run"])
    assert merge.exit_code == 0

    cp1 = runner.invoke(main, ["checkpoint", "--message", "before-diff"])
    assert cp1.exit_code == 0
    vault.ingest("Diff memory payload", source="user")
    cp2 = runner.invoke(main, ["checkpoint", "--message", "after-diff"])
    assert cp2.exit_code == 0

    diff = runner.invoke(main, ["diff", "HEAD~1", "HEAD"])
    assert diff.exit_code == 0

    ms_create = runner.invoke(main, ["milestone", "create", "ms-pre", "--ref", "HEAD~1"])
    assert ms_create.exit_code == 0
    ms_list = runner.invoke(main, ["milestone", "list"])
    assert ms_list.exit_code == 0

    revert = runner.invoke(main, ["revert", "ms-pre"])
    assert revert.exit_code == 0

    verify = runner.invoke(main, ["verify"])
    assert verify.exit_code == 0

    keygen = runner.invoke(main, ["keys", "generate", "default"])
    assert keygen.exit_code == 0

    sync_push = runner.invoke(main, ["sync", "push", "peer-demo", "--out", str(tmp_path / "bundle.csf")])
    assert sync_push.exit_code == 0

    sync_pull = runner.invoke(main, ["sync", "pull", "--bundle", str(tmp_path / "bundle.csf")])
    assert sync_pull.exit_code == 0

    stats = runner.invoke(main, ["stats", "--json"])
    assert stats.exit_code == 0
