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

from .base import Category, ReusableText, ManagedServiceProvider, validate_image_size
from .providers import CloudProvider


class Service(models.Model):
    name = models.CharField(max_length=200)
    slug = models.SlugField(max_length=250, unique=True)
    description = ProseEditorField()
    tagline = models.TextField(max_length=500, blank=True, null=True)
    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 ServiceOffering(models.Model):
    service = models.ForeignKey(
        Service, on_delete=models.CASCADE, related_name="offerings"
    )
    msp = models.CharField(
        "Managed Service Provider",
        max_length=2,
        default=ManagedServiceProvider.VS,
        choices=ManagedServiceProvider.choices,
    )
    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):
        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):
        validate = URLValidator()
        try:
            validate(self.url)
        except ValidationError:
            raise ValidationError({"url": "Enter a valid URL."})
