from django.db import models
from django.utils.text import slugify
from apps.accounts.fields import WebPImageField


class MarketplaceService(models.Model):
    CATEGORY_IT          = 'it'
    CATEGORY_MARKETING   = 'marketing'
    CATEGORY_CREATIVE    = 'creative'
    CATEGORY_DEVELOPMENT = 'development'
    CATEGORY_AI          = 'ai'
    CATEGORY_COMMS       = 'communications'

    CATEGORY_CHOICES = [
        (CATEGORY_IT,          'IT & Infrastructure'),
        (CATEGORY_MARKETING,   'Marketing'),
        (CATEGORY_CREATIVE,    'Creative'),
        (CATEGORY_DEVELOPMENT, 'Development'),
        (CATEGORY_AI,          'AI'),
        (CATEGORY_COMMS,       'Communications'),
    ]

    tenant            = models.ForeignKey(
        'tenants.Tenant', on_delete=models.CASCADE,
        null=True, blank=True, related_name='marketplace_services'
    )
    title             = models.CharField(max_length=150)
    slug              = models.SlugField(max_length=180, blank=True)
    category          = models.CharField(max_length=30, choices=CATEGORY_CHOICES, default=CATEGORY_MARKETING)
    short_description = models.TextField(help_text='Shown on service card')
    full_description  = models.TextField(blank=True)
    icon_class        = models.CharField(max_length=100, blank=True, help_text='FontAwesome class')
    icon_image        = WebPImageField(upload_to='marketplace/icons/', blank=True, null=True)
    starting_price    = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    price_label       = models.CharField(max_length=50, blank=True, help_text='e.g. "from £299"')
    order             = models.PositiveIntegerField(default=1)
    is_active         = models.BooleanField(default=True)
    is_featured       = models.BooleanField(default=False)

    created_at = models.DateTimeField(auto_now_add=True)

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

    def __str__(self):
        return self.title

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

class Plugin(models.Model):
    """
    A curated pointer to something YOUR COMPANY already sells, shown inside a
    tenant's own panel so they never have to visit the website to buy.

    The name, price and description live on the catalogue item, not here. This
    model only decides where a thing appears and how buying it behaves.
    """
    SECTION_SERVER       = 'server'
    SECTION_PANEL        = 'panel'
    SECTION_PRODUCT      = 'product'
    SECTION_SERVICE      = 'service'
    SECTION_SUBSCRIPTION = 'subscription'
    # What a tenant buys from inside their own panel. The three above
    # describe what the item is; this one describes where it is sold.
    SECTION_MARKETPLACE  = 'marketplace'

    SECTION_CHOICES = [
        (SECTION_SERVER,       'Upgrading Server Quality'),
        (SECTION_PANEL,        'Upgrading Panel and Modules'),
        (SECTION_PRODUCT,      'Products'),
        (SECTION_SERVICE,      'Services'),
        (SECTION_SUBSCRIPTION, 'Subscriptions'),
        (SECTION_MARKETPLACE,  'Marketplace'),
    ]

    # How buying behaves. Server and panel work needs a human, so those are
    # requested and invoiced. Catalogue items are bought online and delivered
    # within 24 hours. A module is the only thing that can switch itself on.
    FULFIL_REQUEST = 'request'
    FULFIL_ONLINE  = 'online'
    FULFIL_MODULE  = 'module'

    FULFIL_CHOICES = [
        (FULFIL_REQUEST, 'Request, then we invoice'),
        (FULFIL_ONLINE,  'Buy online, delivered within 24 hours'),
        (FULFIL_MODULE,  'Buy online, switches on immediately'),
    ]

    # What an upgrade points at.
    #
    # Upgrades are not catalogue items. Nothing in products or services
    # describes a bigger server or a higher plan, and the tenant is invoiced
    # for the work rather than charged at a checkout, so pointing an upgrade
    # at a product row was only ever a way of filling a required field.
    SERVER_UPGRADES = [
        ('server_dedicated',   'Dedicated Server'),
        ('server_virtual',     'Virtual Server'),
        ('server_cloud',       'Cloud Server'),
        ('server_application', 'Application Server'),
        ('server_mail',        'Mail Server'),
        ('server_media',       'Media Server'),
    ]
    # Starter is absent on purpose. An upgrade only ever moves a site up.
    # Customised is an upgrade label rather than a plan: it is the entry for
    # work quoted per site, and it does not exist in Tenant.PLAN_CHOICES.
    PLAN_UPGRADES = [
        ('plan_standard',   'Standard'),
        ('plan_signature',  'Signature'),
        ('plan_store',      'Store'),
        ('plan_customised', 'Customised'),
    ]
    UPGRADE_CHOICES = SERVER_UPGRADES + PLAN_UPGRADES

    section    = models.CharField(max_length=20, choices=SECTION_CHOICES)
    fulfilment = models.CharField(max_length=20, choices=FULFIL_CHOICES, default=FULFIL_REQUEST)

    # Exactly one target. A module plugin needs no catalogue row.
    product    = models.ForeignKey(
        'ecommerce.Product', on_delete=models.CASCADE,
        null=True, blank=True, related_name='plugins',
        help_text='Covers products and subscriptions',
    )
    service    = models.ForeignKey(
        'pages.Service', on_delete=models.CASCADE,
        null=True, blank=True, related_name='plugins',
    )
    module_key = models.CharField(
        max_length=40, blank=True,
        help_text='Tenant module this unlocks, e.g. analytics or crm',
    )
    upgrade_key = models.CharField(
        max_length=40, blank=True, choices=UPGRADE_CHOICES,
        help_text='Server type or plan tier this upgrade moves the site to',
    )

    # Optional overrides. Left blank, everything comes from the catalogue item.
    title_override = models.CharField(max_length=150, blank=True)
    blurb          = models.CharField(max_length=250, blank=True, help_text='One line shown on the plugin card')
    price_override = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    price_label    = models.CharField(max_length=60, blank=True, help_text='e.g. from £299 per month')

    visible_plans = models.CharField(
        max_length=200, blank=True,
        help_text='Comma separated plan slugs. Blank means every plan sees it.',
    )
    is_active   = models.BooleanField(default=True)
    is_featured = models.BooleanField(default=False)
    order       = models.PositiveIntegerField(default=1)

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

    class Meta:
        ordering = ['section', 'order', 'id']
        verbose_name = 'Plugin'
        verbose_name_plural = 'Plugins'

    def __str__(self):
        return self.title

    @property
    def target(self):
        return self.product or self.service or None

    @property
    def title(self):
        if self.title_override:
            return self.title_override
        t = self.target
        if t is not None:
            return getattr(t, 'name', None) or getattr(t, 'title', '') or str(t)
        if self.upgrade_key:
            return dict(self.UPGRADE_CHOICES).get(self.upgrade_key, self.upgrade_key)
        return self.module_key.replace('_', ' ').title() or 'Plugin'

    @property
    def kind(self):
        """One word for what this points at. Shown as the Type pill."""
        if self.product:
            return 'Product'
        if self.service:
            return 'Service'
        if self.upgrade_key.startswith('server_'):
            return 'Server'
        if self.upgrade_key.startswith('plan_'):
            return 'Plan'
        if self.module_key:
            return 'Module'
        return ''

    @property
    def price(self):
        if self.price_override is not None:
            return self.price_override
        t = self.target
        return getattr(t, 'price', None) if t is not None else None

    @property
    def annual_price(self):
        """The yearly price of whatever this points at, if it has one."""
        t = self.target
        return getattr(t, 'annual_price', None) if t is not None else None

    def visible_to(self, tenant):
        if not self.is_active or tenant is None:
            return False
        if not self.visible_plans:
            return True
        wanted = [p.strip() for p in self.visible_plans.split(',') if p.strip()]
        return getattr(tenant, 'plan', '') in wanted


class PluginRequest(models.Model):
    """
    A tenant asking for something that cannot be self served: a dedicated
    server, an OS upgrade, a module. YOUR COMPANY accepts, invoices, delivers.
    """
    STATUS_REQUESTED = 'requested'
    STATUS_ACCEPTED  = 'accepted'
    STATUS_DECLINED  = 'declined'
    STATUS_BILLED    = 'billed'
    STATUS_DELIVERED = 'delivered'

    STATUS_CHOICES = [
        (STATUS_REQUESTED, 'Requested'),
        (STATUS_ACCEPTED,  'Accepted'),
        (STATUS_DECLINED,  'Declined'),
        (STATUS_BILLED,    'Invoiced'),
        (STATUS_DELIVERED, 'Delivered'),
    ]

    tenant       = models.ForeignKey('tenants.Tenant', on_delete=models.CASCADE, related_name='plugin_requests')
    plugin       = models.ForeignKey(Plugin, on_delete=models.SET_NULL, null=True, blank=True, related_name='requests')
    plugin_title = models.CharField(max_length=150, help_text='Copied at request time so history survives catalogue edits')
    section      = models.CharField(max_length=20, blank=True)

    requested_by  = models.CharField(max_length=150, blank=True, help_text='Name or username on the tenant side')
    message       = models.TextField(blank=True)

    status        = models.CharField(max_length=20, choices=STATUS_CHOICES, default=STATUS_REQUESTED)
    quoted_amount = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    invoice       = models.ForeignKey(
        'tenants.TenantInvoice', on_delete=models.SET_NULL,
        null=True, blank=True, related_name='plugin_requests',
    )
    ticket        = models.ForeignKey(
        'tickets.Ticket', on_delete=models.SET_NULL,
        null=True, blank=True, related_name='plugin_requests',
    )
    internal_note = models.TextField(blank=True)

    created_at   = models.DateTimeField(auto_now_add=True)
    updated_at   = models.DateTimeField(auto_now=True)
    decided_at   = models.DateTimeField(null=True, blank=True)
    delivered_at = models.DateTimeField(null=True, blank=True)

    class Meta:
        ordering = ['-created_at']
        verbose_name = 'Plugin Request'
        verbose_name_plural = 'Plugin Requests'

    def __str__(self):
        return f'{self.tenant.name} · {self.plugin_title} · {self.get_status_display()}'
