import math
import re

from django.db import models
from django.urls import reverse
from django.utils import timezone
from django.utils.html import strip_tags
from django.utils.text import slugify
from tinymce.models import HTMLField


class Category(models.Model):
    name = models.CharField("Nama kategori", max_length=80, unique=True)
    slug = models.SlugField("Slug", max_length=100, unique=True, blank=True)
    description = models.CharField("Deskripsi", max_length=200, blank=True)
    color = models.CharField("Warna hex", max_length=9, blank=True, default="#F97316")

    class Meta:
        ordering = ["name"]
        verbose_name = "Kategori"
        verbose_name_plural = "Kategori"

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.name)[:100]
        super().save(*args, **kwargs)

    def get_absolute_url(self):
        return f"{reverse('blog:list')}?category={self.slug}"


class Tag(models.Model):
    name = models.CharField("Nama tag", max_length=60, unique=True)
    slug = models.SlugField("Slug", max_length=80, unique=True, blank=True)

    class Meta:
        ordering = ["name"]
        verbose_name = "Tag"
        verbose_name_plural = "Tags"

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.name)[:80]
        super().save(*args, **kwargs)


class PublishedPostManager(models.Manager):
    def get_queryset(self):
        return (
            super()
            .get_queryset()
            .filter(status="published", published_at__lte=timezone.now())
        )


class Post(models.Model):
    STATUS_CHOICES = [
        ("draft", "Draft"),
        ("published", "Terbit"),
    ]
    TYPE_CHOICES = [
        ("article", "Artikel"),
        ("update", "Status Singkat"),
    ]

    title = models.CharField("Judul", max_length=220)
    slug = models.SlugField("Slug", max_length=240, unique=True, blank=True)
    post_type = models.CharField("Tipe", max_length=20, choices=TYPE_CHOICES, default="article")
    cover = models.ImageField("Cover", upload_to="post/", blank=True, null=True)
    excerpt = models.CharField(
        "Ringkasan", max_length=300, blank=True, help_text="Kosongkan untuk auto dari isi"
    )
    content = HTMLField("Isi tulisan")
    category = models.ForeignKey(
        Category,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="posts",
        verbose_name="Kategori",
    )
    tags = models.ManyToManyField(Tag, blank=True, related_name="posts", verbose_name="Tags")
    status = models.CharField("Status", max_length=20, choices=STATUS_CHOICES, default="draft")
    published_at = models.DateTimeField(
        "Waktu terbit", blank=True, null=True, help_text="Isi untuk menjadwalkan terbit"
    )
    is_pinned = models.BooleanField("Pin di atas", default=False)
    allow_comments = models.BooleanField("Izinkan komentar", default=True)
    views_count = models.PositiveIntegerField("Dilihat", default=0)
    likes_count = models.PositiveIntegerField("Suka", default=0)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    objects = models.Manager()
    published = PublishedPostManager()

    class Meta:
        ordering = ["-is_pinned", "-published_at", "-created_at"]
        verbose_name = "Postingan"
        verbose_name_plural = "Postingan"
        indexes = [models.Index(fields=["status", "published_at"])]

    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        if not self.slug:
            base = slugify(self.title)[:200] or "post"
            slug, n = base, 2
            while Post.objects.filter(slug=slug).exclude(pk=self.pk).exists():
                slug = f"{base}-{n}"
                n += 1
            self.slug = slug
        if self.status == "published" and self.published_at is None:
            self.published_at = timezone.now()
        if not self.excerpt:
            self.excerpt = strip_tags(self.content)[:280]
        super().save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse("blog:detail", kwargs={"slug": self.slug})

    @property
    def is_scheduled(self):
        return self.status == "published" and self.published_at and self.published_at > timezone.now()

    @property
    def reading_time(self):
        words = len(re.findall(r"\w+", strip_tags(self.content)))
        return max(1, math.ceil(words / 200))

    @property
    def approved_comments(self):
        return self.comments.filter(is_approved=True, parent__isnull=True)


class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="comments")
    parent = models.ForeignKey(
        "self", on_delete=models.CASCADE, null=True, blank=True, related_name="replies"
    )
    name = models.CharField("Nama", max_length=80)
    email = models.EmailField("Email")
    website = models.URLField("Website", blank=True)
    body = models.TextField("Komentar")
    is_approved = models.BooleanField("Disetujui", default=False)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["created_at"]
        verbose_name = "Komentar"
        verbose_name_plural = "Komentar"

    def __str__(self):
        return f"{self.name} on {self.post}"

    @property
    def initial(self):
        return self.name[:1].upper()
