from __future__ import annotations

import importlib

from typer.testing import CliRunner

from cli.config import CONFIG_DIR_ENV, CLIConfig, ConfigStore


def _reload_cli_module():
    import cli.main as cli_main

    return importlib.reload(cli_main)


def test_ls_command_uses_mock_backend(tmp_path, monkeypatch):
    monkeypatch.setenv(CONFIG_DIR_ENV, str(tmp_path))
    cli_main = _reload_cli_module()

    store = ConfigStore()
    store.save(CLIConfig(default_project="core", use_mock_client=True))

    runner = CliRunner()
    result = runner.invoke(cli_main.app, ["ls"])

    assert result.exit_code == 0
    assert "welcome" in result.stdout


def test_list_command_alias_matches_ls(tmp_path, monkeypatch):
    monkeypatch.setenv(CONFIG_DIR_ENV, str(tmp_path))
    cli_main = _reload_cli_module()

    store = ConfigStore()
    store.save(CLIConfig(default_project="core", use_mock_client=True))

    runner = CliRunner()
    result_ls = runner.invoke(cli_main.app, ["ls"])
    result_list = runner.invoke(cli_main.app, ["list"])

    assert result_ls.exit_code == 0
    assert result_list.exit_code == 0
    assert result_ls.stdout == result_list.stdout


def test_put_command_reads_from_file(tmp_path, monkeypatch):
    monkeypatch.setenv(CONFIG_DIR_ENV, str(tmp_path))
    cli_main = _reload_cli_module()

    store = ConfigStore()
    store.save(CLIConfig(default_project="core", use_mock_client=True))

    data_file = tmp_path / "note.txt"
    data_file.write_text("File-based payload")

    runner = CliRunner()
    result = runner.invoke(cli_main.app, ["put", "note", "--file", str(data_file)])

    assert result.exit_code == 0
    assert "Saved" in result.stdout


def test_search_command_outputs_results(tmp_path, monkeypatch):
    monkeypatch.setenv(CONFIG_DIR_ENV, str(tmp_path))
    cli_main = _reload_cli_module()

    store = ConfigStore()
    store.save(CLIConfig(default_project="core", use_mock_client=True))

    runner = CliRunner()
    result = runner.invoke(cli_main.app, ["search", "welcome"])

    assert result.exit_code == 0
    assert "Search results" in result.stdout


def test_search_all_flag_searches_across_projects(tmp_path, monkeypatch):
    """Test that --all flag searches across all projects."""
    monkeypatch.setenv(CONFIG_DIR_ENV, str(tmp_path))
    cli_main = _reload_cli_module()

    store = ConfigStore()
    store.save(CLIConfig(use_mock_client=True))

    runner = CliRunner()
    # Search for a term that exists in engineering project
    result = runner.invoke(cli_main.app, ["search", "runbook", "--all"])

    assert result.exit_code == 0
    assert "Search results across all projects" in result.stdout
    assert "engineering" in result.stdout
    assert "runbook" in result.stdout


def test_search_all_flag_returns_results_from_multiple_projects(tmp_path, monkeypatch):
    """Test that --all returns results from multiple projects when query matches both."""
    monkeypatch.setenv(CONFIG_DIR_ENV, str(tmp_path))
    cli_main = _reload_cli_module()

    store = ConfigStore()
    store.save(CLIConfig(use_mock_client=True))

    runner = CliRunner()
    # "context" appears in both:
    # - core/welcome data: "This is a placeholder item used by the CLI and MCP scaffolds."
    #   (title contains "Context Platform")
    # - engineering/runbook data: "Capture context"
    result = runner.invoke(cli_main.app, ["search", "context", "--all"])

    assert result.exit_code == 0
    assert "Search results across all projects" in result.stdout
    # Verify results from BOTH projects appear
    assert "core" in result.stdout
    assert "engineering" in result.stdout


def test_search_all_and_project_flags_mutually_exclusive(tmp_path, monkeypatch):
    """Test that --all and --project cannot be used together."""
    monkeypatch.setenv(CONFIG_DIR_ENV, str(tmp_path))
    cli_main = _reload_cli_module()

    store = ConfigStore()
    store.save(CLIConfig(use_mock_client=True))

    runner = CliRunner()
    result = runner.invoke(cli_main.app, ["search", "test", "--all", "--project", "core"])

    assert result.exit_code == 1
    assert "Cannot use --all with --project" in str(result.exception)


def test_search_all_with_limit_caps_results(tmp_path, monkeypatch):
    """Test that --limit caps the number of results returned."""
    monkeypatch.setenv(CONFIG_DIR_ENV, str(tmp_path))
    cli_main = _reload_cli_module()

    store = ConfigStore()
    store.save(CLIConfig(use_mock_client=True))

    runner = CliRunner()

    # First verify "context" matches items in both projects without limit
    result_unlimited = runner.invoke(cli_main.app, ["search", "context", "--all"])
    assert result_unlimited.exit_code == 0
    # Both item keys should appear (welcome from core, runbook from engineering)
    assert "welcome" in result_unlimited.stdout
    assert "runbook" in result_unlimited.stdout

    # Now with limit=1, should only get 1 result
    result_limited = runner.invoke(cli_main.app, ["search", "context", "--all", "--limit", "1"])
    assert result_limited.exit_code == 0
    assert "Search results across all projects" in result_limited.stdout

    # Count item keys - exactly one should appear, not both
    has_welcome = "welcome" in result_limited.stdout
    has_runbook = "runbook" in result_limited.stdout
    assert (
        has_welcome != has_runbook
    ), f"Expected exactly 1 result but got welcome={has_welcome}, runbook={has_runbook}"


def test_search_all_no_matches(tmp_path, monkeypatch):
    """Test --all with no matching results shows appropriate message."""
    monkeypatch.setenv(CONFIG_DIR_ENV, str(tmp_path))
    cli_main = _reload_cli_module()

    store = ConfigStore()
    store.save(CLIConfig(use_mock_client=True))

    runner = CliRunner()
    result = runner.invoke(cli_main.app, ["search", "nonexistentterm12345", "--all"])

    assert result.exit_code == 0
    assert "No matches found across any projects" in result.stdout


def test_search_all_short_flag(tmp_path, monkeypatch):
    """Test that -a short flag works for --all."""
    monkeypatch.setenv(CONFIG_DIR_ENV, str(tmp_path))
    cli_main = _reload_cli_module()

    store = ConfigStore()
    store.save(CLIConfig(use_mock_client=True))

    runner = CliRunner()
    result = runner.invoke(cli_main.app, ["search", "runbook", "-a"])

    assert result.exit_code == 0
    assert "Search results across all projects" in result.stdout
