"""
Tests unitaires pour le module utils.widgets.

Ces tests vérifient le fonctionnement des widgets HTML personnalisés.
"""

import pytest
from unittest.mock import patch, MagicMock
from utils.widgets import html_expander


class TestHtmlExpander:
    """Tests pour la fonction html_expander."""

    @patch('utils.widgets.st')
    @patch('utils.widgets.markdown')
    def test_expander_basic(self, mock_markdown, mock_st):
        """Test la création basique d'un expander."""
        mock_markdown.markdown.return_value = "<p>Test content</p>"

        html_expander("Test Title", "Test content")

        # Vérifier que markdown.markdown a été appelé
        mock_markdown.markdown.assert_called_once_with("Test content")

        # Vérifier que st.markdown a été appelé
        assert mock_st.markdown.called
        call_args = mock_st.markdown.call_args
        html_output = call_args[0][0]

        assert "Test Title" in html_output
        assert "<p>Test content</p>" in html_output
        assert "<details" in html_output
        assert "<summary" in html_output

    @patch('utils.widgets.st')
    @patch('utils.widgets.markdown')
    def test_expander_open_by_default(self, mock_markdown, mock_st):
        """Test un expander ouvert par défaut."""
        mock_markdown.markdown.return_value = "<p>Content</p>"

        html_expander("Title", "Content", open_by_default=True)

        call_args = mock_st.markdown.call_args
        html_output = call_args[0][0]

        assert 'open' in html_output

    @patch('utils.widgets.st')
    @patch('utils.widgets.markdown')
    def test_expander_closed_by_default(self, mock_markdown, mock_st):
        """Test un expander fermé par défaut."""
        mock_markdown.markdown.return_value = "<p>Content</p>"

        html_expander("Title", "Content", open_by_default=False)

        call_args = mock_st.markdown.call_args
        html_output = call_args[0][0]

        # 'open' ne doit pas être dans les attributs si fermé
        # Note: vérifie la logique, pas juste la présence du mot 'open'
        assert '<details id=' in html_output

    @patch('utils.widgets.st')
    @patch('utils.widgets.markdown')
    def test_expander_with_css_classes(self, mock_markdown, mock_st):
        """Test avec des classes CSS personnalisées."""
        mock_markdown.markdown.return_value = "<p>Content</p>"

        html_expander(
            "Title",
            "Content",
            details_class="custom-details",
            summary_class="custom-summary"
        )

        call_args = mock_st.markdown.call_args
        html_output = call_args[0][0]

        assert 'class="custom-details"' in html_output
        assert 'class="custom-summary"' in html_output

    @patch('utils.widgets.st')
    @patch('utils.widgets.markdown')
    @patch('utils.widgets.logger')
    def test_expander_markdown_import_error(self, mock_logger, mock_markdown, mock_st):
        """Test le fallback si markdown n'est pas disponible."""
        # Simuler une ImportError
        mock_markdown.markdown.side_effect = ImportError("Module not found")

        html_expander("Title", "Test\ncontent")

        # Vérifier que le logger a été appelé
        mock_logger.warning.assert_called_once()
        assert "markdown" in mock_logger.warning.call_args[0][0].lower()

        # Vérifier que le fallback HTML a été utilisé
        call_args = mock_st.markdown.call_args
        html_output = call_args[0][0]

        # Le contenu doit être échappé avec <br>
        assert "Test<br>content" in html_output or "Test\ncontent" in html_output

    @patch('utils.widgets.st')
    @patch('utils.widgets.markdown')
    @patch('utils.widgets.logger')
    def test_expander_markdown_other_error(self, mock_logger, mock_markdown, mock_st):
        """Test la gestion d'autres erreurs lors de la conversion markdown."""
        # Simuler une autre exception
        mock_markdown.markdown.side_effect = ValueError("Invalid markdown")

        html_expander("Title", "Content")

        # Vérifier que l'erreur a été loggée
        mock_logger.error.assert_called_once()
        assert "erreur" in mock_logger.error.call_args[0][0].lower()

    @patch('utils.widgets.st')
    @patch('utils.widgets.markdown')
    def test_expander_unique_ids(self, mock_markdown, mock_st):
        """Test que chaque expander a un ID unique."""
        mock_markdown.markdown.return_value = "<p>Content</p>"

        # Créer deux expanders
        html_expander("Title 1", "Content 1")
        call_1 = mock_st.markdown.call_args[0][0]

        html_expander("Title 2", "Content 2")
        call_2 = mock_st.markdown.call_args[0][0]

        # Extraire les IDs
        import re
        id_pattern = r'id="(expander_[a-f0-9]+)"'
        id_1 = re.search(id_pattern, call_1).group(1)
        id_2 = re.search(id_pattern, call_2).group(1)

        # Les IDs doivent être différents
        assert id_1 != id_2

    @patch('utils.widgets.st')
    @patch('utils.widgets.markdown')
    def test_expander_unsafe_html_enabled(self, mock_markdown, mock_st):
        """Test que unsafe_allow_html est activé."""
        mock_markdown.markdown.return_value = "<p>Content</p>"

        html_expander("Title", "Content")

        # Vérifier que unsafe_allow_html=True
        call_kwargs = mock_st.markdown.call_args[1]
        assert call_kwargs.get("unsafe_allow_html") is True

    @patch('utils.widgets.st')
    @patch('utils.widgets.markdown')
    def test_expander_with_special_characters(self, mock_markdown, mock_st):
        """Test avec des caractères spéciaux dans le titre et le contenu."""
        mock_markdown.markdown.return_value = "<p>Content &lt;&gt;</p>"

        html_expander("Title <>&", "Content <>&")

        call_args = mock_st.markdown.call_args
        html_output = call_args[0][0]

        # Le titre doit être présent
        assert "Title <>&" in html_output

    @patch('utils.widgets.st')
    @patch('utils.widgets.markdown')
    def test_expander_empty_content(self, mock_markdown, mock_st):
        """Test avec un contenu vide."""
        mock_markdown.markdown.return_value = ""

        html_expander("Title", "")

        # Ne doit pas crasher
        assert mock_st.markdown.called

    @patch('utils.widgets.st')
    @patch('utils.widgets.markdown')
    def test_expander_multiline_content(self, mock_markdown, mock_st):
        """Test avec du contenu multiligne."""
        content = """
# Titre
Paragraphe 1

Paragraphe 2
"""
        mock_markdown.markdown.return_value = "<h1>Titre</h1><p>Paragraphe 1</p><p>Paragraphe 2</p>"

        html_expander("Title", content)

        call_args = mock_st.markdown.call_args
        html_output = call_args[0][0]

        assert "<h1>Titre</h1>" in html_output
