"""
Tests pour l'application Core
"""
from django.test import TestCase, Client
from django.urls import reverse
from decimal import Decimal

from .models import (
    SiteConfiguration, Partner, CarouselSlide,
    ProgramStatistic, SocialMediaLink, UniversityMapSettings
)
from cms.models import Button, ButtonAssignment


class SiteConfigurationModelTest(TestCase):
    """Tests pour le modèle SiteConfiguration"""

    def test_singleton_creation(self):
        """Test que SiteConfiguration est un singleton"""
        config1 = SiteConfiguration.get_config()
        config2 = SiteConfiguration.get_config()
        self.assertEqual(config1.pk, config2.pk)
        self.assertEqual(SiteConfiguration.objects.count(), 1)

    def test_default_values(self):
        """Test des valeurs par défaut"""
        config = SiteConfiguration.get_config()
        self.assertEqual(config.site_name, 'EUROMA')

    def test_str_representation(self):
        """Test de la représentation string"""
        config = SiteConfiguration.get_config()
        self.assertEqual(str(config), config.site_name)


class PartnerModelTest(TestCase):
    """Tests pour le modèle Partner"""

    def setUp(self):
        self.partner = Partner.objects.create(
            name="European Commission",
            city="Brussels",
            is_main_partner=True,
            latitude=Decimal('50.8503'),
            longitude=Decimal('4.3517')
        )

    def test_partner_creation(self):
        """Test création d'un partenaire"""
        self.assertEqual(self.partner.name, "European Commission")
        self.assertTrue(self.partner.is_main_partner)

    def test_str_representation(self):
        """Test de la représentation string"""
        self.assertEqual(str(self.partner), "European Commission")

    def test_ordering(self):
        """Test de l'ordre des partenaires"""
        partner2 = Partner.objects.create(name="Partner B", order=1)
        partner3 = Partner.objects.create(name="Partner A", order=0)
        partners = list(Partner.objects.all())
        # L'ordre est par order, puis par name
        self.assertEqual(partners[0], self.partner)  # order=0, name="European Commission"
        self.assertEqual(partners[1], partner3)  # order=0, name="Partner A"
        self.assertEqual(partners[2], partner2)  # order=1


class CarouselSlideModelTest(TestCase):
    """Tests pour le modèle CarouselSlide"""

    def setUp(self):
        self.slide = CarouselSlide.objects.create(
            title="Welcome to EUROMA",
            subtitle="European Master Program",
            order=1,
            is_active=True
        )

    def test_slide_creation(self):
        """Test création d'un slide"""
        self.assertEqual(self.slide.title, "Welcome to EUROMA")
        self.assertTrue(self.slide.is_active)

    def test_str_representation(self):
        """Test de la représentation string"""
        self.assertEqual(str(self.slide), "Welcome to EUROMA")

    def test_ordering(self):
        """Test de l'ordre des slides"""
        slide2 = CarouselSlide.objects.create(title="Slide 2", order=0)
        slides = list(CarouselSlide.objects.all())
        self.assertEqual(slides[0], slide2)  # order=0

    def test_get_active_buttons(self):
        """Test de la méthode get_active_buttons avec le nouveau système"""
        # Créer un bouton actif
        button1 = Button.objects.create(
            name="Active Button",
            text="Active Button",
            link_type='external',
            external_url='https://example.com',
            active=True
        )
        # Créer un bouton inactif
        button2 = Button.objects.create(
            name="Inactive Button",
            text="Inactive Button",
            link_type='external',
            external_url='https://example.com',
            active=False
        )
        # Associer les deux boutons au slide
        ButtonAssignment.add_button_to_object(self.slide, button1, order=1)
        ButtonAssignment.add_button_to_object(self.slide, button2, order=2)

        active_buttons = self.slide.get_active_buttons()
        self.assertEqual(len(active_buttons), 1)
        self.assertEqual(active_buttons[0].text, "Active Button")


class ButtonModelTest(TestCase):
    """Tests pour le modèle Button (cms)"""

    def test_external_button_creation(self):
        """Test création d'un bouton avec lien externe"""
        button = Button.objects.create(
            name="Test External",
            text="En savoir plus",
            link_type='external',
            external_url='https://example.com/page',
            active=True
        )
        self.assertEqual(button.text, "En savoir plus")
        self.assertEqual(button.link_type, 'external')
        self.assertEqual(button.get_url(), 'https://example.com/page')

    def test_internal_button_creation(self):
        """Test création d'un bouton avec lien interne"""
        from cms.models import Page, Template
        template = Template.objects.create(
            name="Test Template",
            template_dir="test-btn"
        )
        page = Page.objects.create(
            name="Test Page",
            title="Test Page",
            slug="test-page-btn",
            template=template
        )
        button = Button.objects.create(
            name="Test Internal",
            text="Voir la page",
            link_type='internal',
            internal_page=page,
            active=True
        )
        self.assertEqual(button.link_type, 'internal')
        self.assertIn('test-page-btn', button.get_url())

    def test_named_url_button(self):
        """Test création d'un bouton avec URL nommée"""
        button = Button.objects.create(
            name="Test Named URL",
            text="Contact",
            link_type='url',
            named_url='contact:contact',
            active=True
        )
        self.assertEqual(button.link_type, 'url')
        self.assertIn('contact', button.get_url())

    def test_str_representation(self):
        """Test de la représentation string"""
        button = Button.objects.create(
            name="My Button",
            text="Test Button",
            link_type='external',
            external_url='https://example.com'
        )
        self.assertIn("My Button", str(button))
        self.assertIn("Test Button", str(button))

    def test_style_choices(self):
        """Test des choix de style"""
        for style in ['primary', 'secondary', 'outline', 'dark', 'gradient']:
            button = Button.objects.create(
                name=f"Button {style}",
                text=f"Button {style}",
                link_type='external',
                external_url='https://example.com',
                style=style
            )
            self.assertEqual(button.style, style)

    def test_validation_external_requires_url(self):
        """Test que le lien externe requiert une URL"""
        from django.core.exceptions import ValidationError
        button = Button(
            name="Invalid",
            text="Invalid Button",
            link_type='external',
            external_url=''
        )
        with self.assertRaises(ValidationError):
            button.clean()

    def test_validation_internal_requires_page(self):
        """Test que le lien interne requiert une page"""
        from django.core.exceptions import ValidationError
        button = Button(
            name="Invalid",
            text="Invalid Button",
            link_type='internal',
            internal_page=None
        )
        with self.assertRaises(ValidationError):
            button.clean()

    def test_get_url_fallback(self):
        """Test que get_url retourne # si pas de lien"""
        button = Button(
            name="No URL",
            text="No URL",
            link_type='internal',
            internal_page=None
        )
        self.assertEqual(button.get_url(), '#')

    def test_usage_count(self):
        """Test du compteur d'utilisations"""
        button = Button.objects.create(
            name="Shared Button",
            text="Click me",
            link_type='external',
            external_url='https://example.com'
        )
        slide1 = CarouselSlide.objects.create(title="Slide 1")
        slide2 = CarouselSlide.objects.create(title="Slide 2")

        self.assertEqual(button.get_usage_count(), 0)

        ButtonAssignment.add_button_to_object(slide1, button)
        self.assertEqual(button.get_usage_count(), 1)

        ButtonAssignment.add_button_to_object(slide2, button)
        self.assertEqual(button.get_usage_count(), 2)


class ProgramStatisticModelTest(TestCase):
    """Tests pour le modèle ProgramStatistic"""

    def setUp(self):
        self.stat = ProgramStatistic.objects.create(
            label="Universités",
            value="6",
            order=1,
            is_active=True
        )

    def test_stat_creation(self):
        """Test création d'une statistique"""
        self.assertEqual(self.stat.label, "Universités")
        self.assertEqual(self.stat.value, "6")

    def test_str_representation(self):
        """Test de la représentation string"""
        self.assertIn("6", str(self.stat))
        self.assertIn("Universités", str(self.stat))


class SocialMediaLinkModelTest(TestCase):
    """Tests pour le modèle SocialMediaLink"""

    def test_platform_choices(self):
        """Test des choix de plateforme"""
        link = SocialMediaLink.objects.create(
            platform='linkedin',
            url='https://linkedin.com/company/greentechmobility'
        )
        self.assertEqual(link.get_platform_display(), 'LinkedIn')


class UniversityMapSettingsModelTest(TestCase):
    """Tests pour le modèle UniversityMapSettings"""

    def test_singleton_creation(self):
        """Test que UniversityMapSettings est un singleton"""
        settings1 = UniversityMapSettings.get_settings()
        settings2 = UniversityMapSettings.get_settings()
        self.assertEqual(settings1.pk, settings2.pk)
        self.assertEqual(UniversityMapSettings.objects.count(), 1)

    def test_default_values(self):
        """Test des valeurs par défaut"""
        settings = UniversityMapSettings.get_settings()
        self.assertEqual(settings.default_zoom, 4)
        self.assertEqual(settings.map_style, 'default')
        self.assertTrue(settings.is_active)

    def test_tile_url(self):
        """Test de la méthode get_tile_url"""
        settings = UniversityMapSettings.get_settings()
        settings.map_style = 'default'
        self.assertIn('openstreetmap', settings.get_tile_url())

        settings.map_style = 'light'
        self.assertIn('cartocdn', settings.get_tile_url())

    def test_attribution(self):
        """Test de la méthode get_attribution"""
        settings = UniversityMapSettings.get_settings()
        settings.map_style = 'default'
        self.assertIn('OpenStreetMap', settings.get_attribution())


class HomePageViewTest(TestCase):
    """Tests pour la vue de la page d'accueil"""

    def setUp(self):
        self.client = Client()
        # Créer des données de test
        CarouselSlide.objects.create(
            title="Test Slide",
            is_active=True
        )
        ProgramStatistic.objects.create(
            label="Test Stat",
            value="100",
            is_active=True
        )

    def test_home_page_status_code(self):
        """Test que la page d'accueil retourne 200"""
        response = self.client.get(reverse('core:home'))
        self.assertEqual(response.status_code, 200)

    def test_home_page_template(self):
        """Test du template utilisé"""
        response = self.client.get(reverse('core:home'))
        self.assertTemplateUsed(response, 'core/home.html')

    def test_home_page_context(self):
        """Test du contexte de la page"""
        response = self.client.get(reverse('core:home'))
        self.assertIn('slides', response.context)
        self.assertIn('statistics', response.context)
        self.assertIn('map_settings', response.context)

    def test_carousel_slides_in_context(self):
        """Test que les slides actifs sont dans le contexte"""
        response = self.client.get(reverse('core:home'))
        self.assertEqual(response.context['slides'].count(), 1)

    def test_inactive_slides_not_shown(self):
        """Test que les slides inactifs ne sont pas affichés"""
        CarouselSlide.objects.create(title="Inactive", is_active=False)
        response = self.client.get(reverse('core:home'))
        self.assertEqual(response.context['slides'].count(), 1)
