"""Tests for W3 smart gates tag validation heuristic.

Acoperă:
- infer_tags_from_paths: detect ui/db/vercel pe baza file extensions / paths
- force_include_tags: combinare tags Opus + tags inferate din diff (anti-silent-regression)
- Toate combinatii de tag types (ui, db, vercel, refactor, docs, backend, infra)
- Edge cases: tags vide, tags invalide, empty diff
"""
from __future__ import annotations

import sys
from pathlib import Path

import pytest

PROJECT_ROOT = Path(__file__).resolve().parents[1]
if str(PROJECT_ROOT) not in sys.path:
    sys.path.insert(0, str(PROJECT_ROOT))

from tools.ralph_dag import (  # noqa: E402
    VALID_TAGS,
    force_include_tags,
    infer_tags_from_paths,
)


# ── infer_tags_from_paths ──────────────────────────────────────


class TestInferTags:
    def test_empty_diff_no_tags(self):
        assert infer_tags_from_paths([]) == []

    def test_only_readme_no_tags(self):
        assert infer_tags_from_paths(["README.md", "CHANGELOG.md"]) == []

    def test_vue_triggers_ui(self):
        assert infer_tags_from_paths(["src/App.vue"]) == ["ui"]

    def test_tsx_triggers_ui(self):
        assert infer_tags_from_paths(["app/page.tsx"]) == ["ui"]

    def test_jsx_triggers_ui(self):
        assert infer_tags_from_paths(["src/Button.jsx"]) == ["ui"]

    def test_html_triggers_ui(self):
        assert infer_tags_from_paths(["dashboard/index.html"]) == ["ui"]

    def test_css_scss_trigger_ui(self):
        assert infer_tags_from_paths(["src/main.css"]) == ["ui"]
        assert infer_tags_from_paths(["src/main.scss"]) == ["ui"]

    def test_svelte_triggers_ui(self):
        assert infer_tags_from_paths(["src/App.svelte"]) == ["ui"]

    def test_migrations_triggers_db(self):
        assert infer_tags_from_paths(["db/migrations/0001_init.sql"]) == ["db"]

    def test_top_level_migrations_triggers_db(self):
        assert infer_tags_from_paths(["migrations/2026/04/add_users.sql"]) == ["db"]

    def test_sql_outside_migrations_still_triggers_db(self):
        assert infer_tags_from_paths(["scripts/seed.sql"]) == ["db"]

    def test_vercel_json_only(self):
        assert infer_tags_from_paths([], has_vercel_json=True) == ["vercel"]

    def test_combined_ui_db_vercel(self):
        result = infer_tags_from_paths(
            ["app/page.tsx", "db/migrations/0001.sql"], has_vercel_json=True
        )
        assert result == ["ui", "db", "vercel"]

    def test_dedup_when_multiple_files_same_category(self):
        result = infer_tags_from_paths(["a.tsx", "b.vue", "c.css"])
        assert result == ["ui"]

    def test_case_insensitive_extensions(self):
        assert infer_tags_from_paths(["src/App.TSX"]) == ["ui"]
        assert infer_tags_from_paths(["db/Init.SQL"]) == ["db"]


# ── force_include_tags ─────────────────────────────────────────


class TestForceIncludeTags:
    def test_existing_only_no_diff(self):
        assert force_include_tags(["backend"], [], False) == ["backend"]

    def test_diff_inferred_added_to_existing(self):
        # Opus marcat docs, dar diff atinge .tsx → ui forțat
        result = force_include_tags(["docs"], ["src/Page.tsx"], False)
        assert "docs" in result
        assert "ui" in result

    def test_filters_invalid_tags_from_existing(self):
        # Tag-ul "frontend" nu e în VALID_TAGS — trebuie eliminat
        result = force_include_tags(["frontend", "ui"], [], False)
        assert "frontend" not in result
        assert "ui" in result

    def test_empty_when_no_existing_no_diff(self):
        assert force_include_tags([], [], False) == []

    def test_dedup_existing_and_inferred(self):
        # Existing are ui, diff are .tsx → un singur ui în output
        result = force_include_tags(["ui"], ["src/A.tsx"], False)
        assert result.count("ui") == 1

    def test_vercel_added_when_vercel_json_present(self):
        result = force_include_tags(["backend"], [], has_vercel_json=True)
        assert "vercel" in result
        assert "backend" in result

    def test_all_valid_tags_preserved(self):
        # Verifică că force_include nu strică tags valide existente
        all_valid = list(VALID_TAGS)
        result = force_include_tags(all_valid, [], False)
        for t in all_valid:
            assert t in result

    def test_order_existing_first_then_inferred(self):
        # Existing tags trebuie să apară primele (stabilitate API)
        result = force_include_tags(["backend"], ["src/Page.tsx", "db/migrations/0001.sql"], False)
        assert result[0] == "backend"
        assert "ui" in result and "db" in result


# ── Smart gates dispatcher contract (combinatii tag → expected gates) ─────────


# Acesta e un table-test pentru contractul dispatcher-ului din prompt.md.
# Verifică doar mapping-ul tag → gate name (specifice prompt.md), nu execuția.
GATE_MAPPING = {
    "refactor": "/workflow:simplify",
    "ui": "/qa",
    "vercel": "gh pr checks",
    "db": "schema diff",
    "docs": None,                 # docs => doar typecheck base
    "backend": "/review",
    "infra": "/review",
}


class TestGateMapping:
    """Validează că prompt.md menționează gate-urile așteptate per tag."""

    @pytest.fixture(scope="class")
    def prompt_md(self):
        path = PROJECT_ROOT / "tools" / "ralph" / "prompt.md"
        return path.read_text(encoding="utf-8")

    def test_refactor_gate_documented(self, prompt_md):
        assert "/workflow:simplify" in prompt_md

    def test_ui_gate_documented(self, prompt_md):
        assert "/qa" in prompt_md
        assert "agent-browser" in prompt_md.lower()

    def test_vercel_gate_documented(self, prompt_md):
        assert "gh pr checks" in prompt_md

    def test_db_gate_documented(self, prompt_md):
        assert "schema diff" in prompt_md.lower() or "alembic" in prompt_md.lower()

    def test_backend_gate_documented(self, prompt_md):
        assert "/review" in prompt_md

    def test_run_all_fallback_documented(self, prompt_md):
        # Tags vide → run-all-gates fallback (safe default)
        assert "tags vide" in prompt_md.lower() or "run-all-gates" in prompt_md.lower()

    def test_dag_dependson_documented(self, prompt_md):
        assert "dependsOn" in prompt_md or "DAG" in prompt_md
