from django.db import models
from django.core.exceptions import ValidationError
from django.urls import reverse
from django.utils.text import slugify
from django_prose_editor.fields import ProseEditorField


def validate_image_size(value):
    filesize = value.size
    if filesize > 1 * 1024 * 1024:  # 1MB
        raise ValidationError("Maximum file size is 1MB")


class ReusableText(models.Model):
    name = models.CharField(max_length=100)
    textsnippet = models.ForeignKey(
        "self",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="children",
    )
    text = ProseEditorField()

    class Meta:
        ordering = ["name"]

    def __str__(self):
        return self.name

    def get_full_text(self):
        """Returns the text with all nested textsnippet content recursively included in reverse order"""
        text_parts = []

        # Recursively collect all text parts
        def collect_text(snippet):
            if snippet is None:
                return
            collect_text(snippet.textsnippet)  # Collect deepest snippets first
            text_parts.append(snippet.text)

        # Start collection with the deepest snippets
        collect_text(self.textsnippet)

        # Add the main text at the end
        text_parts.append(self.text)

        # Join all text parts
        return "".join(text_parts)


class Category(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField(unique=True)
    parent = models.ForeignKey(
        "self", on_delete=models.CASCADE, null=True, blank=True, related_name="children"
    )
    description = models.TextField(blank=True)
    order = models.IntegerField(default=0)

    class Meta:
        verbose_name_plural = "Categories"
        ordering = ["order", "name"]

    def __str__(self):
        if self.parent:
            return f"{self.parent} > {self.name}"
        return self.name

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

    @property
    def full_path(self):
        path = [self.name]
        parent = self.parent
        while parent:
            path.append(parent.name)
            parent = parent.parent
        return " > ".join(reversed(path))


class CloudProvider(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField(unique=True)
    description = ProseEditorField()
    website = models.URLField()
    linkedin = models.URLField(blank=True)
    phone = models.CharField(max_length=25, blank=True, null=True)
    email = models.EmailField(max_length=254, blank=True, null=True)
    address = models.TextField(max_length=250, blank=True, null=True)
    logo = models.ImageField(
        upload_to="cloud_provider_logos/",
        validators=[validate_image_size],
        null=True,
        blank=True,
    )
    is_featured = models.BooleanField(default=False)
    disable_listing = models.BooleanField(default=False)

    def __str__(self):
        return self.name

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

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


class Service(models.Model):
    name = models.CharField(max_length=200)
    slug = models.SlugField(max_length=250, unique=True)
    description = ProseEditorField()
    logo = models.ImageField(
        upload_to="service_logos/",
        validators=[validate_image_size],
        null=True,
        blank=True,
    )
    categories = models.ManyToManyField(Category, related_name="services")
    features = ProseEditorField()
    is_featured = models.BooleanField(default=False)
    is_coming_soon = models.BooleanField(default=False)
    disable_listing = models.BooleanField(default=False)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.name

    def clean(self):
        if self.is_featured and self.is_coming_soon:
            raise ValidationError(
                "A service cannot be both featured and coming soon simultaneously."
            )
        super().clean()

    def save(self, *args, **kwargs):
        self.clean()  # Ensure validation runs on save
        if not self.slug:
            self.slug = slugify(self.name)
            counter = 1
            while Service.objects.filter(slug=self.slug).exists():
                self.slug = f"{slugify(self.name)}-{counter}"
                counter += 1
        super().save(*args, **kwargs)

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


class ConsultingPartner(models.Model):
    name = models.CharField(max_length=200)
    slug = models.SlugField(unique=True)
    description = ProseEditorField()
    logo = models.ImageField(
        upload_to="partner_logos/",
        validators=[validate_image_size],
        null=True,
        blank=True,
    )
    website = models.URLField(blank=True)
    linkedin = models.URLField(blank=True)
    phone = models.CharField(max_length=25, blank=True, null=True)
    email = models.EmailField(max_length=254, blank=True, null=True)
    address = models.TextField(max_length=250, blank=True, null=True)

    services = models.ManyToManyField(
        Service, related_name="consulting_partners", blank=True
    )
    cloud_providers = models.ManyToManyField(
        CloudProvider, related_name="consulting_partners", blank=True
    )

    is_featured = models.BooleanField(default=False)
    disable_listing = models.BooleanField(default=False)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.name

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

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


class ServiceOffering(models.Model):
    service = models.ForeignKey(
        Service, on_delete=models.CASCADE, related_name="offerings"
    )
    cloud_provider = models.ForeignKey(
        CloudProvider, on_delete=models.CASCADE, related_name="offerings"
    )
    description = ProseEditorField(blank=True, null=True)
    offer_description = models.ForeignKey(
        ReusableText,
        on_delete=models.PROTECT,
        related_name="offer_descriptions",
        blank=True,
        null=True,
    )

    disable_listing = models.BooleanField(default=False)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        unique_together = ["service", "cloud_provider"]
        ordering = ["service__name", "cloud_provider__name"]

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

    def get_absolute_url(self):
        return reverse(
            "services:offering_detail",
            kwargs={
                "provider_slug": self.cloud_provider.slug,
                "service_slug": self.service.slug,
            },
        )


class Plan(models.Model):
    name = models.CharField(max_length=100)
    description = ProseEditorField(blank=True, null=True)
    pricing = ProseEditorField(blank=True, null=True)
    plan_description = models.ForeignKey(
        ReusableText,
        on_delete=models.PROTECT,
        related_name="plan_descriptions",
        blank=True,
        null=True,
    )
    offering = models.ForeignKey(
        ServiceOffering, on_delete=models.CASCADE, related_name="plans"
    )

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["name"]
        unique_together = [["offering", "name"]]

    def __str__(self):
        return f"{self.offering} - {self.name}"


class ExternalLinkOffering(models.Model):
    offering = models.ForeignKey(
        ServiceOffering, on_delete=models.CASCADE, related_name="external_links"
    )
    url = models.URLField()
    description = models.CharField(max_length=200)
    order = models.IntegerField(default=0)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["order", "description"]
        verbose_name = "External Link"
        verbose_name_plural = "External Links"

    def __str__(self):
        return f"{self.description} ({self.url})"

    def clean(self):
        from django.core.validators import URLValidator

        validate = URLValidator()
        try:
            validate(self.url)
        except ValidationError:
            raise ValidationError({"url": "Enter a valid URL."})


class ExternalLink(models.Model):
    service = models.ForeignKey(
        Service, on_delete=models.CASCADE, related_name="external_links"
    )
    url = models.URLField()
    description = models.CharField(max_length=200)
    order = models.IntegerField(default=0)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["order", "description"]
        verbose_name = "External Link"
        verbose_name_plural = "External Links"

    def __str__(self):
        return f"{self.description} ({self.url})"

    def clean(self):
        from django.core.validators import URLValidator

        validate = URLValidator()
        try:
            validate(self.url)
        except ValidationError:
            raise ValidationError({"url": "Enter a valid URL."})


class Lead(models.Model):
    name = models.CharField(max_length=200)
    email = models.EmailField()
    company = models.CharField(max_length=200, null=True, blank=True)
    phone = models.CharField(max_length=50, null=True, blank=True)
    message = models.TextField(blank=True, null=True, max_length=1000)
    odoo_lead_id = models.IntegerField(null=True, blank=True)

    service = models.ForeignKey(
        Service, on_delete=models.SET_NULL, null=True, blank=True
    )
    offering = models.ForeignKey(
        ServiceOffering, on_delete=models.SET_NULL, null=True, blank=True
    )
    plan = models.ForeignKey(Plan, on_delete=models.SET_NULL, null=True, blank=True)

    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.name} - {self.company} ({self.service})"
