"""
Pages app — CMS-controlled content for every section of the public site.
Multi-tenant: every non-singleton model carries a tenant FK.
Singleton models use TenantSingletonManager so get_or_create is per-tenant.
"""
from django.db import models
from django_ckeditor_5.fields import CKEditor5Field
from apps.accounts.fields import WebPImageField
try:
    from encrypted_model_fields.fields import EncryptedCharField as _EncryptedCharField
    from encrypted_model_fields.fields import EncryptedTextField as _EncryptedTextField
    _HAS_ENCRYPTION = True
except ImportError:
    _HAS_ENCRYPTION = False

def _secure_field(**kwargs):
    """Returns EncryptedCharField if library is installed, else plain CharField."""
    if _HAS_ENCRYPTION:
        return _EncryptedCharField(**kwargs)
    return models.CharField(**kwargs)


def _secure_text(**kwargs):
    """Same, for values too long for a CharField. The Google service account
    key is a 2 KB JSON document, so it cannot use _secure_field."""
    if _HAS_ENCRYPTION:
        return _EncryptedTextField(**kwargs)
    return models.TextField(**kwargs)


# ─── Tenant-aware singleton base ─────────────────────────────────────────────

class TenantSingletonManager(models.Manager):
    """get_or_create pk=1 is replaced by per-tenant get_or_create."""
    pass  # logic handled in TenantSingleton.load()


class TenantSingleton(models.Model):
    """
    Like SingletonModel but per-tenant.
    Each tenant gets exactly ONE row per section type.
    """
    tenant = models.ForeignKey(
        'tenants.Tenant',
        on_delete=models.CASCADE,
        null=True, blank=True,
        related_name='+'
    )

    class Meta:
        abstract = True

    @classmethod
    def load(cls, tenant):
        if tenant is None or (hasattr(tenant, 'pk') and tenant.pk == 0):
            # No real tenant in DB yet — return the existing null-tenant row if any,
            # otherwise return an unsaved instance so the form still renders.
            obj = cls.objects.filter(tenant__isnull=True).first()
            return obj if obj is not None else cls()
        obj, _ = cls.objects.get_or_create(tenant=tenant)
        return obj


# Keep the old SingletonModel for backwards compat (used by SiteSettings)
class SingletonModel(models.Model):
    """Base for singleton models (only one row allowed)."""
    class Meta:
        abstract = True

    def save(self, *args, **kwargs):
        self.pk = 1
        super().save(*args, **kwargs)

    @classmethod
    def load(cls):
        obj, _ = cls.objects.get_or_create(pk=1)
        return obj


# ─── Global Site Settings (per tenant) ───────────────────────────────────────

class SiteSettings(TenantSingleton):
    # Every field below is blank by default. A fresh install must not be born
    # wearing another company's name, phone number or social accounts.
    site_name         = models.CharField(max_length=100, default='')
    tagline           = models.CharField(max_length=200, blank=True)
    site_title_suffix = models.CharField(max_length=200, blank=True, default='', help_text='Text after the site name in the browser tab title (e.g. "Web Portals, Mobile Apps & Digital Marketing")')
    logo            = WebPImageField(upload_to='site/', blank=True, null=True)
    favicon         = WebPImageField(upload_to='site/', blank=True, null=True)
    phone           = models.CharField(max_length=30, blank=True, default='')
    email           = models.EmailField(blank=True, default='')
    address         = models.CharField(max_length=200, blank=True, default='')
    google_maps_url = models.URLField(blank=True)
    # The embed src from Google Maps, Share then Embed a map. Kept separate
    # from the link above because the contact page needs the iframe URL, and
    # a hardcoded one would show a single office on every site.
    google_maps_embed = models.URLField(blank=True, max_length=500)
    working_hours   = models.CharField(max_length=100, blank=True, default='')

    # Social links
    instagram = models.URLField(blank=True, default='')
    facebook  = models.URLField(blank=True, default='')
    twitter   = models.URLField(blank=True, default='')
    linkedin  = models.URLField(blank=True, default='')
    youtube   = models.URLField(blank=True, default='')

    # Analytics / scripts
    google_analytics_id = models.CharField(max_length=30, blank=True)
    google_tag_manager_id = models.CharField(
        max_length=30, blank=True,
        help_text='GTM-XXXXXXX. When set, the page loads this instead of the G- tag, '
                  'so add GA4 as a tag inside the container.')
    recaptcha_site_key  = models.CharField(max_length=100, blank=True)
    meta_description    = models.TextField(blank=True)
    meta_keywords       = models.TextField(blank=True)

    # Stripe
    stripe_public_key      = models.CharField(max_length=200, blank=True, help_text='Stripe publishable key (pk_live_... or pk_test_...)')
    stripe_secret_key      = _secure_field(max_length=200, blank=True, help_text='Stripe secret key — stored encrypted')
    stripe_webhook_secret  = _secure_field(max_length=200, blank=True, help_text='Stripe webhook signing secret (whsec_...)')

    # reCAPTCHA
    recaptcha_secret_key = _secure_field(max_length=200, blank=True, help_text='Google reCAPTCHA v3 secret key — stored encrypted')
    # v2 is the checkbox shown when a v3 score comes back low. Its keys used
    # to be the last two credentials still read from .env.
    recaptcha_v2_site_key   = models.CharField(max_length=100, blank=True, help_text='Google reCAPTCHA v2 site key, used for the fallback checkbox')
    recaptcha_v2_secret_key = _secure_field(max_length=200, blank=True, help_text='Google reCAPTCHA v2 secret key, stored encrypted')

    # Who built this site. Rendered as the last line of every public page,
    # below the client's own footer. Set once by the installer so a new
    # tenant carries it from the first request, and never hardcoded, because
    # this same code is the blank template.
    builder_name = models.CharField(max_length=100, blank=True, help_text='Credit shown in the sub footer, e.g. Designed and Developed by ...')
    builder_url  = models.URLField(blank=True, help_text='Where that credit links to. Opens in a new tab.')

    # FAB Club OAuth. Read by apps.fab_auth.backend, which asks the database
    # before it asks Django settings, so social auth needs nothing in .env.
    fab_oauth_client_id     = models.CharField(max_length=200, blank=True, help_text='OAuth2 client_id issued by FAB Club')
    fab_oauth_client_secret = _secure_field(max_length=255, blank=True, help_text='OAuth2 client secret, stored encrypted')

    # Google Analytics service account. The whole ga_credentials.json document,
    # pasted in. It used to be a file on disk pointed at by GA_CREDENTIALS_FILE,
    # and on the Mac that path had gone stale, so GA failed quietly for weeks.
    ga_credentials_json = _secure_text(blank=True, help_text='Paste the contents of the Google service account JSON file')

    # Twilio — shared credentials for SMS + WhatsApp
    twilio_account_sid  = _secure_field(max_length=100, blank=True, help_text='Twilio Account SID (ACxxxx)')
    twilio_auth_token   = _secure_field(max_length=100, blank=True, help_text='Twilio Auth Token')
    twilio_sms_from     = models.CharField(max_length=30, blank=True, help_text='Twilio SMS from number, e.g. +447700900000')
    twilio_from_number  = models.CharField(max_length=30, blank=True, help_text='Twilio WhatsApp sender, e.g. +14155238886')

    # OpenAI (AI chat widget)
    openai_api_key      = _secure_field(max_length=200, blank=True)
    # OpenAI publishes no balance endpoint, so the panel works it out: the
    # credit you last topped up, minus what has been spent since that date.
    openai_admin_key    = _secure_field(max_length=200, blank=True, help_text='Admin key (sk-admin-...) used only to read the costs endpoint')
    openai_credit       = models.DecimalField(max_digits=9, decimal_places=2, default=0, help_text='Credit balance at the last top-up, in USD')
    openai_credit_date  = models.DateField(null=True, blank=True, help_text='Date of that top-up. Spend is counted from here.')

    # SMTP (outgoing email)
    smtp_host           = models.CharField(max_length=200, blank=True, help_text='e.g. mail.example.com')
    smtp_port           = models.PositiveIntegerField(default=465)
    smtp_user           = models.CharField(max_length=200, blank=True, help_text='e.g. noreply@example.com')
    smtp_password       = _secure_field(max_length=200, blank=True)
    smtp_use_ssl        = models.BooleanField(default=True)
    smtp_use_tls        = models.BooleanField(default=False)
    smtp_from_email     = models.CharField(max_length=200, blank=True, help_text='Deprecated. The sending address is the No-Reply address.')

    # Support mailbox. Ticket replies are read from here over IMAP.
    support_email       = models.CharField(max_length=200, blank=True)
    support_password    = _secure_field(max_length=200, blank=True)
    # Not on the form. Defaults to the SMTP host, which is right unless the
    # two mailboxes sit on different domains.
    support_imap_host   = models.CharField(max_length=200, blank=True)
    support_imap_port   = models.PositiveIntegerField(default=993)

    # Apple PWA / home screen icon
    apple_touch_icon = models.ImageField(upload_to='site/', blank=True, null=True, help_text='180×180 PNG — logo on brand colour background. Shown when users add the site to their iPhone/iPad home screen.')

    # GDPR cookie consent
    cookie_consent_enabled = models.BooleanField(default=False, help_text='Show a cookie consent banner on first visit. Analytics will only load after the visitor accepts.')
    # Wording is editable because consent text is a legal statement about that
    # site's own cookies, and no two clients use the same set.
    cookie_consent_message = models.TextField(
        blank=True,
        help_text='Shown in the banner. Leave blank to use the standard wording.',
    )
    cookie_consent_accept_label = models.CharField(
        max_length=40, blank=True, help_text='Button that accepts everything. Default: Accept All',
    )
    cookie_consent_essential_label = models.CharField(
        max_length=40, blank=True, help_text='Button that accepts essential only. Default: Essential Only',
    )

    # Footer
    footer_tagline       = models.TextField(blank=True)
    footer_tagline_align = models.CharField(max_length=10, default='left', choices=[('left', 'Left'), ('right', 'Right'), ('center', 'Centre'), ('justify', 'Justify')])
    founded_year         = models.IntegerField(null=True, blank=True, default=None)

    # Headings above the footer columns.
    #
    # FooterLink stores which column a link belongs to, but the words at the
    # top of each column were written into the theme, so a site could rename
    # every link underneath and still be headed "Who We Are". Left blank, each
    # theme keeps the heading it already shows.
    footer_col1_title    = models.CharField(max_length=60, blank=True, default='',
                           help_text='Heading above the first link column.')
    footer_col2_title    = models.CharField(max_length=60, blank=True, default='',
                           help_text='Heading above the second link column.')
    footer_col3_title    = models.CharField(max_length=60, blank=True, default='',
                           help_text='Heading above the contact column.')
    footer_copyright     = models.CharField(max_length=200, blank=True, default='',
                           help_text='The line at the bottom. Leave blank to keep the theme default.')

    class Meta:
        verbose_name = 'Site Settings'
        unique_together = [('tenant',)]   # one per tenant

    def __str__(self):
        t = getattr(self, 'tenant', None)
        return f'Site Settings — {t.name if t else "?"}'


# ─── Social Links (drag-orderable, per-tenant) ───────────────────────────────

class SocialLink(models.Model):
    PLATFORM_CHOICES = [
        ('instagram',  'Instagram'),
        ('facebook',   'Facebook'),
        ('twitter',    'X (Twitter)'),
        ('linkedin',   'LinkedIn'),
        ('youtube',    'YouTube'),
        ('tiktok',     'TikTok'),
        ('pinterest',  'Pinterest'),
        ('snapchat',   'Snapchat'),
        ('whatsapp',   'WhatsApp'),
        ('telegram',   'Telegram'),
    ]

    PLATFORM_ICONS = {
        'instagram': 'fa-brands fa-instagram',
        'facebook':  'fa-brands fa-facebook-f',
        'twitter':   'fa-brands fa-x-twitter',
        'linkedin':  'fa-brands fa-linkedin-in',
        'youtube':   'fa-brands fa-youtube',
        'tiktok':    'fa-brands fa-tiktok',
        'pinterest': 'fa-brands fa-pinterest-p',
        'snapchat':  'fa-brands fa-snapchat',
        'whatsapp':  'fa-brands fa-whatsapp',
        'telegram':  'fa-brands fa-telegram',
    }

    tenant    = models.ForeignKey('tenants.Tenant', on_delete=models.CASCADE,
                                  null=True, blank=True, related_name='social_links')
    platform  = models.CharField(max_length=20, choices=PLATFORM_CHOICES)
    url       = models.URLField()
    is_active = models.BooleanField(default=True)
    order     = models.PositiveSmallIntegerField(default=0)

    class Meta:
        ordering = ['order', 'platform']
        verbose_name = 'Social Link'
        verbose_name_plural = 'Social Links'

    def __str__(self):
        return f'{self.get_platform_display()} — {self.url}'

    @property
    def icon_class(self):
        return self.PLATFORM_ICONS.get(self.platform, 'fa-solid fa-link')


# ─── Legal Pages ─────────────────────────────────────────────────────────────

class LegalPage(models.Model):
    SLUG_CHOICES = [
        ('privacy-policy',  'Privacy Policy'),
        ('cookie-policy',   'Cookie Policy'),
        ('terms',           'Terms of Use'),
        ('purchase-policy', 'Purchase Policy'),
    ]

    tenant  = models.ForeignKey(
        'tenants.Tenant', on_delete=models.CASCADE,
        null=True, blank=True, related_name='legal_pages'
    )
    slug       = models.CharField(max_length=30, choices=SLUG_CHOICES)
    title      = models.CharField(max_length=200)
    content    = CKEditor5Field(config_name='extended', blank=True)
    order      = models.IntegerField(default=0)
    is_visible = models.BooleanField(default=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        unique_together = [('tenant', 'slug')]
        ordering = ['order']
        verbose_name = 'Legal Page'
        verbose_name_plural = 'Legal Pages'

    def __str__(self):
        return self.get_slug_display()

    @classmethod
    def load(cls, slug, tenant):
        obj, _ = cls.objects.get_or_create(
            slug=slug, tenant=tenant,
            defaults={'title': dict(cls.SLUG_CHOICES).get(slug, slug)}
        )
        return obj


# ─── Homepage — Hero ─────────────────────────────────────────────────────────

class HomeHero(TenantSingleton):
    heading_line1         = models.CharField(max_length=100, blank=True, default='')
    heading_accent        = models.CharField(max_length=100, blank=True, default='')
    heading_line2         = models.CharField(max_length=100, blank=True, default='',
                            help_text='Second line of the homepage headline. Left blank on a new install so the hero never carries somebody else\'s name.')
    description           = models.TextField(default='')
    trusted_clients_count = models.CharField(max_length=20, blank=True, default='')
    trusted_clients_label = models.CharField(max_length=50, blank=True, default='')
    video                 = models.FileField(upload_to='hero/', blank=True, null=True)
    video_url             = models.URLField(blank=True)
    portfolio_btn_text    = models.CharField(max_length=50, blank=True, default='')
    play_btn_url          = models.URLField(blank=True)

    badge_1 = models.CharField(max_length=50, blank=True, default='')
    badge_2 = models.CharField(max_length=50, blank=True, default='')
    badge_3 = models.CharField(max_length=50, blank=True, default='')

    class Meta:
        verbose_name = 'Homepage Hero'
        unique_together = [('tenant',)]

    def __str__(self):
        return 'Homepage Hero'


# ─── Homepage — Hero slides ──────────────────────────────────────────────────

class HomeSlide(models.Model):
    """
    One panel of the homepage carousel.

    HomeHero holds a single headline and a video, which suits a hero that does
    not move. A site whose hero is a slider had nowhere to put the second and
    third panel, so those lived in the template and the Homepage editor could
    not touch them. MOSTAFAEI is the case that surfaced it: About, Services and
    Portfolio all followed the panel while the three slides stayed frozen in
    the file.

    Rows are optional. With none, a theme falls back to whatever its hero
    already renders, so adding this table changes nothing on a site until
    somebody adds a slide.

    headline and headline_em are separate because the design italicises the
    second half. Storing one string and splitting it in the template would
    guess at where the emphasis belongs.
    """
    tenant = models.ForeignKey(
        'tenants.Tenant', on_delete=models.CASCADE,
        null=True, blank=True, related_name='home_slides'
    )
    image       = WebPImageField(upload_to='slides/', blank=True, null=True,
                  help_text='Background image. Landscape, at least 1600px wide.')
    label       = models.CharField(max_length=80, blank=True, default='',
                  help_text='Small line above the headline, e.g. Business Group.')
    headline    = models.CharField(max_length=160, blank=True, default='')
    headline_em = models.CharField(max_length=160, blank=True, default='',
                  help_text='Second part of the headline, shown emphasised on its own line.')
    body        = models.TextField(blank=True, default='')

    btn1_text   = models.CharField(max_length=60, blank=True, default='')
    btn1_url    = models.CharField(max_length=300, blank=True, default='',
                  help_text='A path such as #portfolio or /services/, or a full address.')
    btn2_text   = models.CharField(max_length=60, blank=True, default='')
    btn2_url    = models.CharField(max_length=300, blank=True, default='')

    order       = models.PositiveIntegerField(default=1)
    is_active   = models.BooleanField(default=True)
    created_at  = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['order', 'id']
        verbose_name = 'Homepage Slide'
        verbose_name_plural = 'Homepage Slides'

    def __str__(self):
        return self.headline or self.label or f'Slide {self.pk}'


# ─── Homepage — About ─────────────────────────────────────────────────────────

class HomeAbout(TenantSingleton):
    heading    = models.CharField(max_length=200, blank=True, default='')
    # The emphasised second line of the About heading, matching how HomeSlide
    # splits headline from headline_em. The design sets it on its own line in
    # the accent style, and storing one string would force the template to
    # guess where the emphasis begins.
    heading_em = models.CharField(max_length=200, blank=True, default='',
                 help_text='Second line of the heading, shown emphasised.')
    body       = models.TextField(default='')
    image      = WebPImageField(upload_to='about/', blank=True, null=True)
    card_number = models.CharField(max_length=20, blank=True, default='')
    card_label  = models.CharField(max_length=50, blank=True, default='')
    card_sub    = models.CharField(max_length=50, blank=True, default='')

    # The small line above the heading and the button under the copy. Both were
    # written into the template, so the About editor could change the words in
    # the middle of the section but not the label on top or the button at the
    # bottom of the same block.
    section_tag = models.CharField(max_length=80, blank=True, default='',
                  help_text='Small line above the heading, e.g. Who We Are.')
    btn_text    = models.CharField(max_length=60, blank=True, default='')
    btn_url     = models.CharField(max_length=300, blank=True, default='',
                  help_text='A path such as #portfolio, or a full address.')

    class Meta:
        verbose_name = 'Homepage About'
        unique_together = [('tenant',)]

    def __str__(self):
        return 'Homepage About'


# ─── Homepage — Founder ──────────────────────────────────────────────────────

class HomeFounder(TenantSingleton):
    """
    The message from the founder, one block per tenant.

    heading and heading_em are split for the same reason HomeAbout splits them:
    the design sets the second word in the accent colour, and one string would
    force the template to guess where the emphasis begins.

    quote is its own field rather than the first line of the body, because the
    design styles it as a pulled quote above the copy.
    """
    section_tag = models.CharField(max_length=80, blank=True, default='',
                  help_text='Small line above the heading.')
    heading     = models.CharField(max_length=200, blank=True, default='')
    heading_em  = models.CharField(max_length=200, blank=True, default='',
                  help_text='End of the heading, shown in the accent colour.')
    quote       = models.TextField(blank=True, default='',
                  help_text='The line in quotation marks above the copy.')
    body        = CKEditor5Field(config_name='extended', blank=True)
    photo       = WebPImageField(upload_to='founder/', blank=True, null=True)
    photo_alt   = models.CharField(max_length=200, blank=True, default='',
                  help_text='Describes the photo for search engines and screen readers.')
    signature   = WebPImageField(upload_to='founder/', blank=True, null=True)
    signature_alt = models.CharField(max_length=200, blank=True, default='',
                    help_text='Describes the signature image.')
    is_active   = models.BooleanField(default=True)

    class Meta:
        verbose_name = 'Homepage Founder'
        unique_together = [('tenant',)]

    def __str__(self):
        return 'Homepage Founder'


# ─── Homepage — Counter ──────────────────────────────────────────────────────

class HomeCounter(models.Model):
    """
    One figure in the band of statistics under the hero.

    number and suffix are separate because the design counts up to the number
    and holds the suffix still. Storing "26+" as one string would animate the
    plus sign along with the digits, or force the template to strip it back
    off again.
    """
    tenant = models.ForeignKey(
        'tenants.Tenant', on_delete=models.CASCADE,
        null=True, blank=True, related_name='home_counters'
    )
    number    = models.PositiveIntegerField(default=0,
                help_text='Counts up to this from zero.')
    suffix    = models.CharField(max_length=8, blank=True, default='',
                help_text='Held still beside the number, usually + or %. Leave blank for none.')
    label     = models.CharField(max_length=80)
    order     = models.PositiveIntegerField(default=1)
    is_active = models.BooleanField(default=True)

    class Meta:
        ordering = ['order', 'id']
        verbose_name = 'Homepage Counter'
        verbose_name_plural = 'Homepage Counters'

    def __str__(self):
        return f'{self.number}{self.suffix} {self.label}'


# ─── Homepage — Services header ──────────────────────────────────────────────

class HomeServices(TenantSingleton):
    """
    The heading block above the service cards.

    The cards themselves have been editable since the beginning while the
    three lines introducing them sat in the template, so a site could rename
    every service and still be introduced by somebody else's words.
    """
    section_tag = models.CharField(max_length=80, blank=True, default='',
                  help_text='Small line above the heading, e.g. What We Do.')
    heading     = models.CharField(max_length=200, blank=True, default='')
    heading_em  = models.CharField(max_length=200, blank=True, default='',
                  help_text='Emphasised end of the heading, shown in the accent style.')
    subtitle    = models.TextField(blank=True, default='')

    class Meta:
        verbose_name = 'Homepage Services Header'
        unique_together = [('tenant',)]

    def __str__(self):
        return 'Homepage Services Header'


# ─── Services ─────────────────────────────────────────────────────────────────

class ServiceCategory(models.Model):
    tenant = models.ForeignKey(
        'tenants.Tenant', on_delete=models.CASCADE,
        null=True, blank=True, related_name='service_categories'
    )
    name       = models.CharField(max_length=100)
    slug       = models.SlugField(max_length=120)
    icon_class = models.CharField(max_length=100, blank=True, help_text='FontAwesome class e.g. fa-solid fa-server')
    order      = models.PositiveIntegerField(default=1)

    class Meta:
        ordering = ['order']
        unique_together = [('tenant', 'slug')]
        verbose_name = 'Service Category'
        verbose_name_plural = 'Service Categories'

    def __str__(self):
        return self.name


class Service(models.Model):
    tenant      = models.ForeignKey(
        'tenants.Tenant', on_delete=models.CASCADE,
        null=True, blank=True, related_name='services'
    )
    category    = models.ForeignKey(
        ServiceCategory, on_delete=models.SET_NULL,
        null=True, blank=True, related_name='services'
    )
    title        = models.CharField(max_length=100)
    description  = models.TextField()
    body         = models.TextField(blank=True, help_text='Full detail page content (supports HTML)')
    icon         = WebPImageField(upload_to='services/icons/', blank=True, null=True)
    icon_class   = models.CharField(max_length=100, blank=True, help_text='FontAwesome class e.g. fa-solid fa-server')
    order        = models.PositiveIntegerField(default=1)
    is_active           = models.BooleanField(default=True)
    show_on_home        = models.BooleanField(default=True, help_text='Show in homepage services section')
    service_page_active = models.BooleanField(default=False, help_text='Enable the detail page for this service')
    slug                = models.SlugField(max_length=150)
    link                = models.CharField(max_length=200, blank=True, default='#services')

    # SEO
    meta_title       = models.CharField(max_length=70, blank=True, help_text='SEO title (30-60 chars)')
    meta_description = models.TextField(blank=True, help_text='Meta description (50-160 chars)')
    focus_keyword    = models.CharField(max_length=100, blank=True)
    canonical_url    = models.URLField(blank=True, help_text='Leave empty to auto-generate from page URL')
    og_image_url     = models.URLField(blank=True, help_text='Social share image (WhatsApp, LinkedIn, X). Leave empty to use service icon.')
    target_region    = models.CharField(max_length=10, blank=True, default='global',
                           choices=[
                               ('global', 'Global'), ('europe', 'Europe'),
                               ('uk', 'United Kingdom'), ('ir', 'Iran'), ('gcc', 'GCC'),
                           ])
    seo_score        = models.PositiveSmallIntegerField(default=0, editable=False,
                           help_text='Auto-computed 0-100 SEO score.')

    class Meta:
        ordering = ['order']
        unique_together = [('tenant', 'slug')]
        verbose_name = 'Service'
        verbose_name_plural = 'Services'

    def __str__(self):
        return self.title

    def compute_seo_score(self):
        checks = [
            bool(self.title),
            30 <= len(self.meta_title) <= 60,
            50 <= len(self.meta_description) <= 160,
            bool(self.focus_keyword),
            bool(self.icon),
            True,   # TL;DR — auto-passes (not configured for services)
            True,   # Tags  — auto-passes (not configured for services)
            bool(self.description),
            bool(self.og_image_url) or bool(self.icon),
            bool(self.service_page_active),
        ]
        passed = sum(1 for c in checks if c)
        return round(passed / len(checks) * 100)

    def save(self, *args, **kwargs):
        update_fields = kwargs.get('update_fields')
        if update_fields is None or 'seo_score' in update_fields:
            self.seo_score = self.compute_seo_score()
        super().save(*args, **kwargs)


# ─── Homepage — First CTA ─────────────────────────────────────────────────────

class HomeCTA1(TenantSingleton):
    word1    = models.CharField(max_length=50, default='Time')
    word2    = models.CharField(max_length=50, default='2')
    word3    = models.CharField(max_length=50, default='Talk')
    body     = models.TextField(default='')
    btn_text = models.CharField(max_length=50, blank=True, default='')
    btn_url  = models.CharField(max_length=200, default='/contact/')

    class Meta:
        verbose_name = 'Homepage CTA 1 (Time 2 Talk)'
        unique_together = [('tenant',)]

    def __str__(self):
        return 'CTA 1 — Time 2 Talk'


# ─── Homepage — Process ───────────────────────────────────────────────────────

class HomeProcess(TenantSingleton):
    heading   = models.CharField(max_length=200, blank=True, default='')
    sub_label = models.CharField(max_length=50, blank=True, default='')

    step1_title = models.CharField(max_length=80, default='Discover')
    step1_body  = models.TextField(default='')
    step1_icon  = WebPImageField(upload_to='process/', blank=True, null=True)

    step2_title = models.CharField(max_length=80, default='Design')
    step2_body  = models.TextField(default='')
    step2_icon  = WebPImageField(upload_to='process/', blank=True, null=True)

    step3_title = models.CharField(max_length=80, default='Develop')
    step3_body  = models.TextField(default='')
    step3_icon  = WebPImageField(upload_to='process/', blank=True, null=True)

    class Meta:
        verbose_name = 'Homepage Process'
        unique_together = [('tenant',)]

    def __str__(self):
        return 'Homepage Process'


# ─── Homepage — Why Choose US ─────────────────────────────────────────────────

class HomeWhyChooseUs(TenantSingleton):
    heading        = models.CharField(max_length=200, blank=True, default='')
    # The emphasised end of the heading, shown in the accent colour, matching
    # HomeAbout.heading_em and HomeSlide.headline_em.
    heading_em     = models.CharField(max_length=200, blank=True, default='',
                     help_text='End of the heading, shown in the accent colour.')
    sub_label      = models.CharField(max_length=50, blank=True, default='')
    body           = models.TextField(default='')
    image          = WebPImageField(upload_to='whychooseus/', blank=True, null=True)
    rating_score   = models.CharField(max_length=10, blank=True, default='')
    rating_label   = models.CharField(max_length=50, blank=True, default='')
    rating_body    = models.TextField(blank=True, default='')
    satisfied_pct  = models.CharField(max_length=10, blank=True, default='')
    satisfied_label = models.CharField(max_length=80, blank=True, default='')
    satisfied_body  = models.TextField(blank=True, default='')

    class Meta:
        verbose_name = 'Homepage Why Choose US'
        unique_together = [('tenant',)]

    def __str__(self):
        return 'Homepage Why Choose US'


class WhyChooseUsBox(models.Model):
    tenant    = models.ForeignKey(
        'tenants.Tenant', on_delete=models.CASCADE,
        null=True, blank=True, related_name='why_boxes'
    )
    title     = models.CharField(max_length=100)
    body      = models.TextField()
    icon      = WebPImageField(upload_to='whychooseus/icons/', blank=True, null=True)
    order     = models.PositiveIntegerField(default=1)
    is_active = models.BooleanField(default=True)

    class Meta:
        ordering = ['order']
        verbose_name = 'Why Choose US Box'
        verbose_name_plural = 'Why Choose US Boxes'

    def __str__(self):
        return self.title


# ─── Homepage — Second CTA (Startup) ─────────────────────────────────────────

class HomeCTA2(TenantSingleton):
    heading  = models.CharField(max_length=200, blank=True, default='')
    body     = models.TextField(default='')
    btn_text = models.CharField(max_length=50, blank=True, default='')
    btn_url  = models.CharField(max_length=200, default='/startup/')

    class Meta:
        verbose_name = 'Homepage CTA 2 (Startup)'
        unique_together = [('tenant',)]

    def __str__(self):
        return 'CTA 2 — Startup'


# ─── Homepage — Testimonials intro ───────────────────────────────────────────

class HomeTestimonials(TenantSingleton):
    heading           = models.CharField(max_length=200, blank=True, default='')
    body              = models.TextField(default='')
    image             = WebPImageField(upload_to='testimonials/', blank=True, null=True)
    google_review_url = models.URLField(max_length=500, blank=True, help_text='Google review or search link. These run long, hence 500.')

    class Meta:
        verbose_name = 'Homepage Testimonials Section'
        unique_together = [('tenant',)]

    def __str__(self):
        return 'Testimonials Section'


class Testimonial(models.Model):
    tenant      = models.ForeignKey(
        'tenants.Tenant', on_delete=models.CASCADE,
        null=True, blank=True, related_name='testimonials'
    )
    name        = models.CharField(max_length=100)
    company     = models.CharField(max_length=100, blank=True)
    designation = models.CharField(max_length=100, blank=True)
    photo       = WebPImageField(upload_to='testimonials/photos/', blank=True, null=True)
    quote       = models.TextField()
    star_rating = models.PositiveSmallIntegerField(default=5, choices=[(i, i) for i in range(1, 6)])
    show_on_home = models.BooleanField(default=True)
    order       = models.PositiveIntegerField(default=1)
    is_active   = models.BooleanField(default=True)
    created_at  = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['order']
        verbose_name = 'Testimonial'
        verbose_name_plural = 'Testimonials'

    def __str__(self):
        return f'{self.name} — {self.company}'


# ─── Partner Logos ────────────────────────────────────────────────────────────

class PartnerLogo(models.Model):
    TYPE_PARTNER = 'partner'
    TYPE_CLIENT  = 'client'
    TYPE_CHOICES = [
        (TYPE_PARTNER, 'Partner'),
        (TYPE_CLIENT,  'Client'),
    ]

    tenant    = models.ForeignKey(
        'tenants.Tenant', on_delete=models.CASCADE,
        null=True, blank=True, related_name='partner_logos'
    )
    name      = models.CharField(max_length=100)
    logo      = WebPImageField(upload_to='partners/')
    url       = models.URLField(blank=True)
    logo_type = models.CharField(max_length=10, choices=TYPE_CHOICES, default=TYPE_PARTNER)
    order     = models.PositiveIntegerField(default=1)
    is_active = models.BooleanField(default=True)

    class Meta:
        ordering = ['order']
        verbose_name = 'Partner / Client Logo'
        verbose_name_plural = 'Partner / Client Logos'

    def __str__(self):
        return f'[{self.get_logo_type_display()}] {self.name}'


# ─── Footer Links (drag-orderable, per-tenant) ───────────────────────────────

class FooterLink(models.Model):
    COLUMN_WHO_WE_ARE    = 'who_we_are'
    COLUMN_PRODUCTS      = 'products'
    COLUMN_SERVICES      = 'services'
    COLUMN_SUBSCRIPTIONS = 'subscriptions'
    COLUMN_ENGAGE        = 'engage'

    # Four link columns, named after what the footer actually shows, and in
    # the order it shows them.
    #
    # Products and Subscriptions were dropped from the choices at some point
    # while the public template kept rendering them, so those two columns
    # appeared on the site with no way to edit them from the panel. The names
    # here have to match the headings a visitor sees, otherwise the panel
    # says Expertise and the footer says Services.
    #
    # Engage is not offered. It is the contact block, address, phone and the
    # enquiry link, all of which come from Settings, and it takes no links.
    COLUMN_CHOICES = [
        (COLUMN_WHO_WE_ARE,    'Who We Are'),
        (COLUMN_SERVICES,      'Services'),
        (COLUMN_PRODUCTS,      'Products'),
        (COLUMN_SUBSCRIPTIONS, 'Subscriptions'),
    ]

    TARGET_SELF  = '_self'
    TARGET_BLANK = '_blank'
    TARGET_CHOICES = [
        (TARGET_SELF,  'Same tab'),
        (TARGET_BLANK, 'New tab'),
    ]

    tenant    = models.ForeignKey(
        'tenants.Tenant', on_delete=models.CASCADE,
        null=True, blank=True, related_name='footer_links'
    )
    column    = models.CharField(max_length=20, choices=COLUMN_CHOICES)
    label     = models.CharField(max_length=100)
    url       = models.CharField(max_length=200)
    target    = models.CharField(max_length=10, choices=TARGET_CHOICES, default='_self')
    order     = models.PositiveIntegerField(default=0)
    is_active = models.BooleanField(default=True)

    class Meta:
        ordering = ['column', 'order']
        verbose_name = 'Footer Link'
        verbose_name_plural = 'Footer Links'

    def __str__(self):
        return f'[{self.get_column_display()}] {self.label}'
