from django.core.exceptions import ValidationError
from django.db import models
from django.utils.text import slugify
from django_ckeditor_5.fields import CKEditor5Field

from apps.accounts.fields import WebPImageField


# A Brand is served from the top level of the domain, so its slug competes with
# every route in config/urls.py. Anything here would shadow a real page, and the
# failure would look like the site randomly losing its contact form.
#
# Keep this in step with config/urls.py. It is checked on save rather than only
# in the form, because a slug can also arrive from a script or the admin.
RESERVED_SLUGS = {
    'admin', 'api', 'auction', 'auth', 'brands', 'chat', 'ckeditor5', 'cms',
    'contact', 'deal', 'fab', 'faq', 'insights', 'login', 'logout',
    'marketplace', 'media', 'my-account', 'portfolio', 'products', 'quote',
    'renew', 'robots.txt', 'services', 'shop', 'sitemap.xml', 'social',
    'startup', 'static', 'stream', 'terms', 'privacy-policy', 'cookie-policy',
    'purchase-policy', 'assessment', 'watch',
}


class Brand(models.Model):
    """One sub-brand of a group, served at /<slug>/ on the parent domain.

    This is deliberately NOT a Tenant. A Tenant is one install, one database
    and one `is_master` row. A Brand is a section inside a single install, so
    a group with eight sub-brands keeps one panel, one login and one set of
    content, which is the entire reason a holding company wants a single site
    rather than eight.

    The two will look alike in the panel. They are not interchangeable, and
    confusing them is how a group ends up with eight databases it did not want.
    """

    tenant = models.ForeignKey(
        'tenants.Tenant', on_delete=models.CASCADE,
        null=True, blank=True, related_name='brands',
    )

    name = models.CharField(max_length=120)
    slug = models.SlugField(
        max_length=140, blank=True,
        help_text='The path this brand is served at, e.g. events gives /events/',
    )
    tagline = models.CharField(
        max_length=200, blank=True,
        help_text='One line under the name, e.g. Where Music Comes Alive',
    )
    intro = models.TextField(
        blank=True, help_text='Short summary, used on the brands index and in cards',
    )
    body = CKEditor5Field(config_name='extended', blank=True)

    logo = WebPImageField(upload_to='brands/logos/', blank=True, null=True)
    hero = WebPImageField(upload_to='brands/hero/', blank=True, null=True)

    accent_colour = models.CharField(
        max_length=9, blank=True,
        help_text='Hex, e.g. #f06820. Falls back to the site accent when blank.',
    )

    # Recorded rather than used. The redirects themselves live at the edge, but
    # writing the domain here keeps one list instead of two that drift apart.
    external_domain = models.CharField(
        max_length=190, blank=True,
        help_text='The domain that redirects here, e.g. hpevents.uk. Recorded, not served.',
    )

    meta_description = models.TextField(blank=True)
    meta_keywords = models.TextField(blank=True)

    order = models.PositiveIntegerField(default=99)
    is_active = models.BooleanField(default=True)
    show_on_home = models.BooleanField(
        default=True, help_text='Include in the brands row on the homepage',
    )

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

    class Meta:
        ordering = ['order', 'name']
        unique_together = [('tenant', 'slug')]
        verbose_name = 'Brand'
        verbose_name_plural = 'Brands'

    def __str__(self):
        return self.name

    def clean(self):
        candidate = (self.slug or slugify(self.name) or '').strip('/').lower()
        if candidate in RESERVED_SLUGS:
            raise ValidationError({
                'slug': f'"{candidate}" is a route this site already uses. '
                        'Pick another, or that page would disappear.'
            })

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

    def get_absolute_url(self):
        return f'/{self.slug}/'
