from django.db import models

from wagtail.models import Page
from wagtail.fields import RichTextField, StreamField
from wagtail.admin.panels import FieldPanel, MultiFieldPanel
from wagtail.search import index
from wagtail.blocks import RichTextBlock, CharBlock, TextBlock, StructBlock, StaticBlock, URLBlock, BooleanBlock
from wagtail.images.blocks import ImageChooserBlock
from wagtail.snippets.models import register_snippet

from modelcluster.fields import ParentalKey, ParentalManyToManyField
from modelcluster.contrib.taggit import ClusterTaggableManager
from taggit.models import TaggedItemBase


class NewsletterCTABlock(StructBlock):
    """Block for inserting newsletter signup form in article content."""
    title = CharBlock(
        required=False,
        max_length=100,
        label="Titre",
        help_text="Laisse vide pour le titre par défaut"
    )
    subtitle = CharBlock(
        required=False,
        max_length=200,
        label="Sous-titre",
        help_text="Laisse vide pour le texte par défaut"
    )

    class Meta:
        icon = "mail"
        label = "Inscription Newsletter"
        template = "blog/blocks/newsletter_cta.html"


class ExternalLinkBlock(StructBlock):
    """Block for external links with sponsored/nofollow options."""
    url = URLBlock(label="URL du lien")
    text = CharBlock(max_length=200, label="Texte du lien")
    is_sponsored = BooleanBlock(
        required=False,
        default=False,
        label="Lien sponsorisé",
        help_text="Ajoute rel='sponsored' pour les liens d'affiliation"
    )
    open_in_new_tab = BooleanBlock(
        required=False,
        default=True,
        label="Ouvrir dans un nouvel onglet"
    )

    class Meta:
        icon = "link-external"
        label = "Lien externe"
        template = "blog/blocks/external_link.html"


@register_snippet
class BlogCategory(models.Model):
    """Category for blog articles."""
    name = models.CharField(max_length=100, verbose_name="Nom")
    slug = models.SlugField(unique=True, max_length=100)
    description = models.TextField(blank=True, verbose_name="Description")

    panels = [
        FieldPanel('name'),
        FieldPanel('slug'),
        FieldPanel('description'),
    ]

    class Meta:
        verbose_name = "Catégorie"
        verbose_name_plural = "Catégories"
        ordering = ['name']

    def __str__(self):
        return self.name


class BlogPageTag(TaggedItemBase):
    """Tag for blog articles."""
    content_object = ParentalKey(
        'BlogPage',
        related_name='tagged_items',
        on_delete=models.CASCADE
    )


class BlogIndexPage(Page):
    """Blog listing page."""
    intro = RichTextField(blank=True, verbose_name="Introduction")

    content_panels = Page.content_panels + [
        FieldPanel('intro'),
    ]

    def get_context(self, request):
        context = super().get_context(request)
        # Get all published blog pages, ordered by date
        blogpages = self.get_children().live().order_by('-first_published_at')
        context['blogpages'] = blogpages
        return context

    class Meta:
        verbose_name = "Page liste blog"


class BlogPage(Page):
    """Individual blog article page."""

    # Content
    excerpt = models.TextField(
        max_length=300,
        verbose_name="Extrait",
        help_text="Court résumé affiché dans les listes (max 300 caractères)"
    )
    featured_image = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+',
        verbose_name="Image à la une"
    )
    body = StreamField([
        ('paragraph', RichTextBlock(
            features=['h2', 'h3', 'bold', 'italic', 'link', 'ol', 'ul', 'blockquote'],
            label="Paragraphe"
        )),
        ('image', ImageChooserBlock(label="Image")),
        ('quote', TextBlock(label="Citation")),
        ('newsletter_cta', NewsletterCTABlock()),
        ('external_link', ExternalLinkBlock()),
    ], use_json_field=True, verbose_name="Contenu")

    # Classification
    categories = ParentalManyToManyField('blog.BlogCategory', blank=True, verbose_name="Catégories")
    tags = ClusterTaggableManager(through=BlogPageTag, blank=True)

    # SEO
    meta_description = models.CharField(
        max_length=160,
        blank=True,
        verbose_name="Meta description",
        help_text="Description pour les moteurs de recherche (max 160 caractères)"
    )

    # Settings
    is_featured = models.BooleanField(default=False, verbose_name="Article vedette")
    view_count = models.PositiveIntegerField(default=0, verbose_name="Nombre de vues")

    # Search
    search_fields = Page.search_fields + [
        index.SearchField('excerpt'),
        index.SearchField('body'),
    ]

    # Panels
    content_panels = Page.content_panels + [
        FieldPanel('excerpt'),
        FieldPanel('featured_image'),
        FieldPanel('body'),
        MultiFieldPanel([
            FieldPanel('categories'),
            FieldPanel('tags'),
        ], heading="Classification"),
    ]

    promote_panels = Page.promote_panels + [
        FieldPanel('meta_description'),
    ]

    settings_panels = Page.settings_panels + [
        FieldPanel('is_featured'),
    ]

    parent_page_types = ['blog.BlogIndexPage']
    subpage_types = []

    class Meta:
        verbose_name = "Article de blog"
        verbose_name_plural = "Articles de blog"

    def serve(self, request):
        """Override serve to track page views."""
        # Only count views for non-bot, non-preview requests
        if not request.user.is_authenticated and 'bot' not in request.META.get('HTTP_USER_AGENT', '').lower():
            self.view_count += 1
            BlogPage.objects.filter(pk=self.pk).update(view_count=self.view_count)
        return super().serve(request)

    @property
    def reading_time(self):
        """Estimate reading time in minutes."""
        word_count = 0
        for block in self.body:
            if block.block_type == 'paragraph':
                word_count += len(str(block.value).split())
        return max(1, round(word_count / 200))

    def increment_view_count(self):
        """Increment view count for this article."""
        self.view_count += 1
        self.save(update_fields=['view_count'])

    @classmethod
    def get_popular(cls, count=5):
        """Get most popular articles by view count."""
        return cls.objects.live().order_by('-view_count')[:count]

    def get_related(self, count=3):
        """Get related articles based on shared tags/categories."""
        # Get articles with same tags
        tag_ids = self.tags.values_list('id', flat=True)
        related = BlogPage.objects.live().exclude(pk=self.pk)

        if tag_ids:
            related = related.filter(tags__in=tag_ids).distinct()

        # If not enough, add from same categories
        if related.count() < count:
            cat_ids = self.categories.values_list('id', flat=True)
            if cat_ids:
                more = BlogPage.objects.live().exclude(pk=self.pk).filter(
                    categories__in=cat_ids
                ).exclude(pk__in=related).distinct()
                related = list(related) + list(more)

        return related[:count]
