"""
═══════════════════════════════════════════════════════════════════════════════
 ARGUS — Tests unitaires pour validate_yaml.py
 Couvre : YAMLValidator, find_project_root
═══════════════════════════════════════════════════════════════════════════════
"""

import pytest
from pathlib import Path

# Import du module sous test
from validate_yaml import YAMLValidator


# ═══════════════════════════════════════════════════════════════════════════════
#  VALIDATION DE FICHIERS INDIVIDUELS
# ═══════════════════════════════════════════════════════════════════════════════


class TestValidateFile:
    """Tests pour YAMLValidator.validate_file()."""

    def test_valid_yaml_file(self, tmp_project):
        """Un fichier YAML valide doit retourner True."""
        validator = YAMLValidator(str(tmp_project), verbose=False)
        filepath = tmp_project / "argus.persona.yaml"
        assert validator.validate_file(filepath) is True
        assert validator.valid_count == 1
        assert len(validator.errors) == 0

    def test_empty_yaml_file(self, tmp_project):
        """Un fichier YAML vide est considéré valide (techniquement correct)."""
        empty = tmp_project / "empty.yaml"
        empty.write_text("", encoding="utf-8")
        validator = YAMLValidator(str(tmp_project), verbose=False)
        assert validator.validate_file(empty) is True
        # valid_count NOT incremented for empty files
        assert validator.valid_count == 0

    def test_whitespace_only_yaml(self, tmp_project):
        """Un fichier avec uniquement des espaces/retours à la ligne est vide."""
        ws = tmp_project / "whitespace.yaml"
        ws.write_text("   \n\n  \n", encoding="utf-8")
        validator = YAMLValidator(str(tmp_project), verbose=False)
        assert validator.validate_file(ws) is True

    def test_invalid_yaml_syntax(self, tmp_project):
        """Un fichier avec une erreur de syntaxe YAML doit retourner False."""
        bad = tmp_project / "bad.yaml"
        bad.write_text("key: value\n  bad_indent: oops\n    - broken", encoding="utf-8")
        validator = YAMLValidator(str(tmp_project), verbose=False)
        assert validator.validate_file(bad) is False
        assert len(validator.errors) == 1
        assert "bad.yaml" in validator.errors[0][0]

    def test_invalid_yaml_tabs(self, tmp_project):
        """Les tabulations sont interdites en YAML (erreur de syntaxe)."""
        tabbed = tmp_project / "tabbed.yaml"
        tabbed.write_text("key:\n\tvalue: oops", encoding="utf-8")
        validator = YAMLValidator(str(tmp_project), verbose=False)
        assert validator.validate_file(tabbed) is False
        assert len(validator.errors) == 1

    def test_nonexistent_file(self, tmp_project):
        """Un fichier inexistant doit retourner False et enregistrer une erreur."""
        validator = YAMLValidator(str(tmp_project), verbose=False)
        missing = tmp_project / "ghost.yaml"
        assert validator.validate_file(missing) is False
        assert len(validator.errors) == 1

    def test_complex_valid_yaml(self, tmp_project):
        """Un fichier YAML complexe avec ancres, multi-ligne, etc. doit être valide."""
        complex_file = tmp_project / "complex.yaml"
        complex_file.write_text(
            "---\n"
            "list:\n"
            "  - item1\n"
            "  - item2\n"
            "nested:\n"
            "  deep:\n"
            "    value: 42\n"
            "multiline: |\n"
            "  line one\n"
            "  line two\n"
            "boolean: true\n"
            "null_val: null\n",
            encoding="utf-8",
        )
        validator = YAMLValidator(str(tmp_project), verbose=False)
        assert validator.validate_file(complex_file) is True

    def test_unicode_content(self, tmp_project):
        """Un fichier avec des caractères Unicode (accents, emojis) doit être valide."""
        uni = tmp_project / "unicode.yaml"
        uni.write_text(
            "nom: \"Éléphant\"\ndesc: \"Les yeux d'Argus 👁️\"\n",
            encoding="utf-8",
        )
        validator = YAMLValidator(str(tmp_project), verbose=False)
        assert validator.validate_file(uni) is True


# ═══════════════════════════════════════════════════════════════════════════════
#  VALIDATION DE RÉPERTOIRE
# ═══════════════════════════════════════════════════════════════════════════════


class TestValidateDirectory:
    """Tests pour YAMLValidator.validate_directory()."""

    def test_all_valid_files(self, tmp_project):
        """Un répertoire avec uniquement des YAML valides retourne True."""
        validator = YAMLValidator(str(tmp_project), verbose=False)
        assert validator.validate_directory() is True
        assert validator.valid_count > 0
        assert len(validator.errors) == 0

    def test_mixed_valid_invalid(self, tmp_project):
        """Un répertoire avec un fichier invalide retourne False."""
        bad = tmp_project / "memory" / "broken.yaml"
        bad.write_text(":\n  :\n  - [invalid", encoding="utf-8")
        validator = YAMLValidator(str(tmp_project), verbose=False)
        assert validator.validate_directory() is False
        assert len(validator.errors) >= 1

    def test_no_yaml_files(self, tmp_path):
        """Un répertoire sans fichier YAML retourne True."""
        empty_dir = tmp_path / "empty"
        empty_dir.mkdir()
        validator = YAMLValidator(str(empty_dir), verbose=False)
        assert validator.validate_directory() is True

    def test_subdirectory_scanning(self, tmp_project):
        """Les fichiers dans les sous-répertoires sont aussi scannés."""
        validator = YAMLValidator(str(tmp_project), verbose=False)
        validator.validate_directory()
        # Le projet contient des YAML dans memory/semantic/, memory/projects/, etc.
        assert validator.valid_count >= 5

    def test_git_directory_excluded(self, tmp_project):
        """Les fichiers dans .git/ sont exclus de la validation."""
        git_dir = tmp_project / ".git" / "hooks"
        git_dir.mkdir(parents=True)
        (git_dir / "fake.yaml").write_text("invalid: \n\t bad", encoding="utf-8")
        validator = YAMLValidator(str(tmp_project), verbose=False)
        assert validator.validate_directory() is True

    def test_specific_subdirectory(self, tmp_project):
        """Valider uniquement un sous-répertoire spécifique."""
        validator = YAMLValidator(str(tmp_project), verbose=False)
        semantic_dir = tmp_project / "memory" / "semantic"
        assert validator.validate_directory(semantic_dir) is True
        # Doit avoir validé les fichiers sémantiques uniquement
        assert validator.valid_count >= 2


# ═══════════════════════════════════════════════════════════════════════════════
#  FORMAT DES ERREURS
# ═══════════════════════════════════════════════════════════════════════════════


class TestErrorFormatting:
    """Tests pour _format_yaml_error()."""

    def test_error_contains_line_number(self, tmp_project):
        """Le message d'erreur doit contenir le numéro de ligne."""
        bad = tmp_project / "lineerr.yaml"
        bad.write_text("ok: value\nbad:\n  - [unclosed\n", encoding="utf-8")
        validator = YAMLValidator(str(tmp_project), verbose=False)
        validator.validate_file(bad)
        assert len(validator.errors) == 1
        _, error_msg = validator.errors[0]
        assert "Line" in error_msg or "line" in error_msg.lower()


# ═══════════════════════════════════════════════════════════════════════════════
#  RÉSUMÉ
# ═══════════════════════════════════════════════════════════════════════════════


class TestPrintSummary:
    """Tests pour print_summary() — vérifie l'absence d'exception."""

    def test_summary_no_errors(self, tmp_project, capsys):
        """Le résumé sans erreur ne lève pas d'exception."""
        validator = YAMLValidator(str(tmp_project), verbose=True)
        validator.validate_directory()
        validator.print_summary()
        captured = capsys.readouterr()
        assert "All YAML files are valid" in captured.out

    def test_summary_with_errors(self, tmp_project, capsys):
        """Le résumé avec erreurs affiche les détails."""
        bad = tmp_project / "err.yaml"
        bad.write_text("bad: \n\t oops", encoding="utf-8")
        validator = YAMLValidator(str(tmp_project), verbose=True)
        validator.validate_directory()
        validator.print_summary()
        captured = capsys.readouterr()
        assert "ERROR DETAILS" in captured.out


# ═══════════════════════════════════════════════════════════════════════════════
#  MODES VERBOSE / QUIET
# ═══════════════════════════════════════════════════════════════════════════════


class TestVerbosity:
    """Tests pour le mode verbose/quiet."""

    def test_quiet_mode_suppresses_output(self, tmp_project, capsys):
        """En mode quiet, aucune sortie standard n'est produite (hors force)."""
        validator = YAMLValidator(str(tmp_project), verbose=False)
        validator.validate_directory()
        validator.print_summary()
        captured = capsys.readouterr()
        # Seuls les messages avec force=True s'affichent
        assert "VALIDATION SUMMARY" not in captured.out

    def test_verbose_mode_produces_output(self, tmp_project, capsys):
        """En mode verbose, la sortie contient des détails."""
        validator = YAMLValidator(str(tmp_project), verbose=True)
        validator.validate_directory()
        captured = capsys.readouterr()
        assert "OK:" in captured.out or "Scanning" in captured.out
