# #region Test.Assistant.CommandParser [C:2] [TYPE Module] [SEMANTICS test,assistant,command,parser,nlu]
# @BRIEF Tests for _command_parser.py — deterministic RU/EN command parser.
# @RELATION BINDS_TO -> [AssistantCommandParser]
# @TEST_EDGE: help_variants -> All help phrases map to show_capabilities
# @TEST_EDGE: status_variants -> Status commands get_task_status with/without task_id
# @TEST_EDGE: branch_create -> Branch create with dashboard_id
# @TEST_EDGE: commit_variants -> Commit with quoted message
# @TEST_EDGE: deploy_variants -> Deploy with env, production detection
# @TEST_EDGE: migrate_variants -> Migration with src/tgt/dry_run/replace_db
# @TEST_EDGE: backup_variants -> Backup with env
# @TEST_EDGE: health_variants -> Health check with env
# @TEST_EDGE: validation_variants -> LLM validation with provider
# @TEST_EDGE: documentation_variants -> LLM documentation with dataset_id
# @TEST_EDGE: fallback -> Unknown commands return clarify intent

from pathlib import Path
import sys

sys.path.insert(0, str(Path(__file__).parent.parent / "src"))

from unittest.mock import MagicMock
import pytest


def _make_config_manager(envs=None):
    cm = MagicMock()
    envs = envs or []
    cm.get_environments = MagicMock(return_value=envs)
    return cm


def _make_env(id_, name_, stage="DEV", is_production=False, is_default=False):
    env = MagicMock()
    env.id = id_
    env.name = name_
    env.stage = stage
    env.is_production = is_production
    env.is_default = is_default
    return env


class TestParseCommandHelp:
    """_parse_command — help/capabilities variants."""

    @pytest.mark.parametrize("msg", [
        "что ты умеешь",
        "что умеешь",
        "что ты можешь",
        "help",
        "помощь",
        "доступные команды",
        "какие команды",
    ])
    def test_help_variants(self, msg):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command(msg, cm)
        assert result["domain"] == "assistant"
        assert result["operation"] == "show_capabilities"
        assert result["entities"] == {}
        assert result["confidence"] == 0.98
        assert result["risk_level"] == "safe"
        assert result["requires_confirmation"] is False


class TestParseCommandStatus:
    """_parse_command — status/task status variants."""

    @pytest.mark.parametrize("msg,expected_conf", [
        ("статус", 0.66),
        ("status", 0.66),
        ("state", 0.66),
        ("проверь задачу", 0.66),
        ("статус task-abc123", 0.92),
        ("status task-abc-def", 0.92),
    ])
    def test_status_variants(self, msg, expected_conf):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command(msg, cm)
        assert result["domain"] == "status"
        assert result["operation"] == "get_task_status"
        assert result["confidence"] == expected_conf
        assert result["risk_level"] == "safe"


class TestParseCommandBranch:
    """_parse_command — branch create variants."""

    @pytest.mark.parametrize("msg,expected_branch,expected_conf", [
        ("создай ветку feature/test", "feature/test", 0.7),
        ("create branch feature/abc", "feature/abc", 0.7),
        ("сделай ветку fix/123 для дашборд 42", "fix/123", 0.95),
        ("create branch main", "main", 0.7),
    ])
    def test_branch_create(self, msg, expected_branch, expected_conf):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command(msg, cm)
        assert result["domain"] == "git"
        assert result["operation"] == "create_branch"
        assert result["risk_level"] == "guarded"
        assert result["confidence"] == expected_conf


class TestParseCommandCommit:
    """_parse_command — commit variants."""

    def test_commit_with_message(self):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command('commit "update dashboard filters"', cm)
        assert result["operation"] == "commit_changes"
        assert result["entities"]["message"] == "update dashboard filters"

    def test_commit_without_quotes(self):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command("commit", cm)
        assert result["operation"] == "commit_changes"
        assert result["entities"]["message"] == "assistant: update dashboard changes"


class TestParseCommandDeploy:
    """_parse_command — deploy variants with production detection."""

    def test_deploy_to_dev(self):
        from src.api.routes.assistant._command_parser import _parse_command
        envs = [_make_env("dev", "DEV", stage="DEV")]
        cm = _make_config_manager(envs)
        result = _parse_command("деплой дашборд 42 в dev", cm)
        assert result["operation"] == "deploy_dashboard"
        assert result["risk_level"] == "guarded"
        assert result["requires_confirmation"] is False

    def test_deploy_to_production(self):
        from src.api.routes.assistant._command_parser import _parse_command
        prod = _make_env("prod", "PROD", stage="PROD", is_production=True)
        cm = _make_config_manager([prod])
        result = _parse_command("deploy dashboard 42 в prod", cm)
        assert result["operation"] == "deploy_dashboard"
        assert result["risk_level"] == "dangerous"
        assert result["requires_confirmation"] is True

    def test_deploy_without_env(self):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command("разверн дашборд 42", cm)
        assert result["operation"] == "deploy_dashboard"
        assert result["confidence"] == 0.7


class TestParseCommandMigration:
    """_parse_command — migration variants."""

    def test_migration_with_src_tgt(self):
        from src.api.routes.assistant._command_parser import _parse_command
        envs = [_make_env("prod", "PROD", stage="PROD", is_production=True)]
        cm = _make_config_manager(envs)
        result = _parse_command("миграц дашборд 42 с dev на prod", cm)
        assert result["operation"] == "execute_migration"
        assert result["entities"]["source_env"] == "dev"
        assert result["entities"]["target_env"] == "prod"
        assert result["risk_level"] == "dangerous"  # because tgt=prod

    def test_migration_dry_run(self):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command("migrate dashboard 42 from dev to staging --dry-run", cm)
        assert result["entities"]["dry_run"] is True
        assert result["entities"]["replace_db_config"] is False
        assert result["entities"]["fix_cross_filters"] is True

    def test_migration_replace_db(self):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command("миграция дашборд 42 с dev на qa --replace-db-config --no-fix-cross-filters", cm)
        assert result["entities"]["replace_db_config"] is True
        assert result["entities"]["fix_cross_filters"] is False

    def test_migration_without_dashboard(self):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command("migrate from dev to staging", cm)
        assert result["confidence"] == 0.72


class TestParseCommandBackup:
    """_parse_command — backup variants."""

    @pytest.mark.parametrize("msg,expected_env", [
        ("бэкап в dev", "dev"),
        ("backup for prod", "prod"),
        ("резерв из staging", "staging"),
        ("бэкап", None),
    ])
    def test_backup(self, msg, expected_env):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command(msg, cm)
        assert result["operation"] == "run_backup"
        assert result["entities"].get("environment") == expected_env
        assert result["risk_level"] == "guarded"


class TestParseCommandHealth:
    """_parse_command — health check variants."""

    @pytest.mark.parametrize("msg,expected_env", [
        ("здоровье в dev", "dev"),
        ("health for prod", "prod"),
        ("ошибки", None),
        ("failing env staging", "staging"),
        ("проблемы", None),
    ])
    def test_health(self, msg, expected_env):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command(msg, cm)
        assert result["domain"] == "health"
        assert result["operation"] == "get_health_summary"
        assert result["entities"].get("environment") == expected_env
        assert result["risk_level"] == "safe"


class TestParseCommandValidation:
    """_parse_command — LLM validation variants."""

    def test_validation_with_provider(self):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command("валидац дашборд 42 для env dev провайдер openai", cm)
        assert result["operation"] == "run_llm_validation"
        assert result["entities"]["environment"] == "dev"
        assert result["entities"]["provider"] == "openai"

    def test_validation_without_env(self):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        # "проверь" alone without a dashboard id -> low confidence
        result = _parse_command("проверь", cm)
        assert result["operation"] == "run_llm_validation"
        assert result["confidence"] == 0.64


class TestParseCommandDocumentation:
    """_parse_command — LLM documentation variants."""

    def test_documentation_with_dataset(self):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command("документац датасет 123 env prod провайдер anthropic", cm)
        assert result["operation"] == "run_llm_documentation"
        assert result["entities"]["dataset_id"] == 123
        assert result["entities"]["environment"] == "prod"
        assert result["entities"]["provider"] == "anthropic"

    def test_documentation_without_dataset(self):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command("generate docs", cm)
        assert result["operation"] == "run_llm_documentation"
        assert result["confidence"] == 0.64


class TestParseCommandSearchDashboards:
    """_parse_command — search/list dashboards."""

    @pytest.mark.parametrize("msg,expected_env", [
        ("список дашборд в dev", "dev"),
        ("покажи дашборд в prod", "prod"),
        ("найди дашборд test в staging", "staging"),
        ("list dashboard в dev", "dev"),
        ("search dashboard covid в dev", "dev"),
        ("all dashboards", None),
        ("все дашборд", None),
    ])
    def test_search_dashboards(self, msg, expected_env):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command(msg, cm)
        assert result["domain"] == "dashboards"
        assert result["operation"] == "search_dashboards"
        assert result["entities"].get("environment") == expected_env


class TestParseCommandEnvironments:
    """_parse_command — list environments."""

    @pytest.mark.parametrize("msg", [
        "окружени",
        "environment",
        "среды",
        "сред",
    ])
    def test_list_environments(self, msg):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command(msg, cm)
        assert result["domain"] == "environments"
        assert result["operation"] == "list_environments"
        assert result["risk_level"] == "safe"


class TestParseCommandMaintenance:
    """_parse_command — maintenance/events."""

    @pytest.mark.parametrize("msg", [
        "обслуживан",
        "maintenance",
        "события",
    ])
    def test_list_maintenance(self, msg):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command(msg, cm)
        assert result["domain"] == "maintenance"
        assert result["operation"] == "list_maintenance_events"


class TestParseCommandLlmProviders:
    """_parse_command — LLM provider listing/status."""

    def test_list_providers(self):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command("llm провайдер", cm)
        assert result["domain"] == "llm"
        assert result["operation"] == "list_llm_providers"

    def test_llm_status_unreachable_via_parser(self):
        """The deterministic parser cannot deliver get_llm_status because all
        keywords matching line 99 are intercepted by earlier checks (status,
        validation). This is a known source-code quirk; LLM status routing
        happens through the LLM planner path instead."""
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command("llm провер", cm)
        # Line 74 (провер in validation) catches it first
        assert result["operation"] == "run_llm_validation"


class TestParseCommandFallback:
    """_parse_command — unknown commands return clarify intent."""

    @pytest.mark.parametrize("msg", [
        "",
        "hello world",
        "какой сегодня день",
        "random gibberish xyz",
        "12345",
    ])
    def test_fallback_to_clarify(self, msg):
        from src.api.routes.assistant._command_parser import _parse_command
        cm = _make_config_manager()
        result = _parse_command(msg, cm)
        assert result["domain"] == "unknown"
        assert result["operation"] == "clarify"
        assert result["confidence"] == 0.3
        assert result["risk_level"] == "safe"
        assert "domain" in result
        assert "operation" in result
        assert "entities" in result
        assert "confidence" in result
        assert "risk_level" in result
        assert "requires_confirmation" in result
# #endregion Test.Assistant.CommandParser
