"""
Module Registry Models - Module registration, licensing, and feature flags.

This module manages:
- Module definitions (installed modules in the platform)
- Tenant module licensing (which tenants have access to which modules)
- Feature flags (enable/disable features per tenant)
- Module dependencies and compatibility
"""
from django.db import models
from django.core.validators import RegexValidator

from apps.core.tenant.models import TenantAwareModel


class ModuleStatus(models.TextChoices):
    """Module installation status."""
    ACTIVE = 'active', 'Active'
    INACTIVE = 'inactive', 'Inactive'
    DEPRECATED = 'deprecated', 'Deprecated'
    BETA = 'beta', 'Beta'
    COMING_SOON = 'coming_soon', 'Coming Soon'


class ModuleCategory(models.TextChoices):
    CORE = 'core', 'Core'
    OPTIONAL = 'optional', 'Optional'
    ENTERPRISE = 'enterprise', 'Enterprise'


class LicenseType(models.TextChoices):
    """Module license types."""
    FREE = 'free', 'Free'
    TRIAL = 'trial', 'Trial'
    BASIC = 'basic', 'Basic'
    PROFESSIONAL = 'professional', 'Professional'
    ENTERPRISE = 'enterprise', 'Enterprise'
    CUSTOM = 'custom', 'Custom'


class Module(models.Model):
    """
    Module definition - represents an installed module in the platform.
    
    This is the central registry of all available modules.
    Each module must register here to be recognized by the platform.
    """
    
    # Basic Information
    name = models.CharField(
        max_length=100,
        unique=True,
        validators=[RegexValidator(
            regex=r'^[a-z][a-z0-9_]*$',
            message='Module name must be lowercase alphanumeric with underscores'
        )],
        help_text="Unique module identifier (e.g., 'accounting', 'hrm')"
    )
    display_name = models.CharField(
        max_length=255,
        help_text="Human-readable name"
    )
    code = models.CharField(
        max_length=100,
        blank=True,
        help_text="Short code (inventory, plm, hr, accounting, project, ...)"
    )
    is_core = models.BooleanField(
        default=False,
        help_text="Core modules cannot be disabled"
    )
    description = models.TextField(
        blank=True,
        help_text="Module description"
    )
    version = models.CharField(
        max_length=50,
        default='1.0.0',
        help_text="Current module version (semver)"
    )
    
    # Status
    status = models.CharField(
        max_length=20,
        choices=ModuleStatus.choices,
        default=ModuleStatus.ACTIVE
    )
    
    # Categorization
    module_category = models.CharField(
        max_length=20,
        choices=ModuleCategory.choices,
        default=ModuleCategory.OPTIONAL,
        help_text="core / optional / enterprise"
    )
    category = models.CharField(
        max_length=100,
        blank=True,
        help_text="Functional category (e.g., 'Finance', 'HR', 'Operations')"
    )
    tags = models.JSONField(
        default=list,
        blank=True,
        help_text="Tags for filtering and searching"
    )
    
    # Icons and Branding
    icon = models.CharField(
        max_length=100,
        blank=True,
        help_text="Icon name or path"
    )
    color = models.CharField(
        max_length=20,
        blank=True,
        help_text="Primary color for the module"
    )
    
    # Dependencies
    dependencies = models.ManyToManyField(
        'self',
        symmetrical=False,
        blank=True,
        related_name='dependents',
        help_text="Other modules this module depends on"
    )
    
    # Configuration
    default_settings = models.JSONField(
        default=dict,
        blank=True,
        help_text="Default settings for this module"
    )
    
    # API Information
    api_prefix = models.CharField(
        max_length=100,
        blank=True,
        help_text="API URL prefix (e.g., '/api/v1/accounting')"
    )
    supported_api_versions = models.JSONField(
        default=list,
        blank=True,
        help_text="List of supported API versions"
    )
    
    # Permissions this module provides
    provided_permissions = models.JSONField(
        default=list,
        blank=True,
        help_text="List of permission codenames this module provides"
    )
    
    # Events this module publishes/consumes
    published_events = models.JSONField(
        default=list,
        blank=True,
        help_text="Events this module publishes"
    )
    consumed_events = models.JSONField(
        default=list,
        blank=True,
        help_text="Events this module consumes"
    )
    
    # Metadata from manifest.json
    manifest = models.JSONField(
        default=dict,
        blank=True,
        help_text="Full manifest.json content"
    )
    
    # Timestamps
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        db_table = 'modules'
        verbose_name = 'Module'
        verbose_name_plural = 'Modules'
        ordering = ['category', 'display_name']
    
    def __str__(self):
        return f"{self.display_name} ({self.name})"
    
    def get_all_dependencies(self) -> set:
        """Get all dependencies recursively."""
        all_deps = set()
        
        def collect_deps(module):
            for dep in module.dependencies.all():
                if dep.pk not in all_deps:
                    all_deps.add(dep.pk)
                    collect_deps(dep)
        
        collect_deps(self)
        return Module.objects.filter(pk__in=all_deps)


class TenantModule(models.Model):
    """
    Tenant module license - tracks which modules a tenant has access to.
    
    This controls:
    - Which modules are enabled for a tenant
    - License type and expiration
    - Module-specific settings per tenant
    """
    
    tenant = models.ForeignKey(
        'tenant.Tenant',
        on_delete=models.CASCADE,
        related_name='licensed_modules'
    )
    module = models.ForeignKey(
        Module,
        on_delete=models.CASCADE,
        related_name='tenant_licenses'
    )
    
    # License Information
    is_enabled = models.BooleanField(
        default=True,
        help_text="Is this module enabled for the tenant?"
    )
    license_type = models.CharField(
        max_length=20,
        choices=LicenseType.choices,
        default=LicenseType.TRIAL
    )
    
    # License info
    license_key = models.CharField(
        max_length=255,
        blank=True,
        help_text="License key (optional)"
    )

    # License Period
    licensed_at = models.DateTimeField(
        auto_now_add=True,
        help_text="When the license was granted"
    )
    expires_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When the license expires (null = never)"
    )

    # Who enabled it
    enabled_by = models.ForeignKey(
        'core_auth.User',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='enabled_modules',
        help_text="User who enabled this module"
    )
    enabled_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When the module was enabled"
    )

    # Usage Limits (optional)
    max_users = models.PositiveIntegerField(
        null=True,
        blank=True,
        help_text="Maximum users for this module (null = unlimited)"
    )
    max_records = models.PositiveIntegerField(
        null=True,
        blank=True,
        help_text="Maximum records (null = unlimited)"
    )
    license_limit = models.JSONField(
        default=dict,
        blank=True,
        help_text="Additional license limits: {api_calls, projects, ...}"
    )

    # Config override per tenant
    config_override = models.JSONField(
        default=dict,
        blank=True,
        help_text="Tenant-specific configuration overrides"
    )

    # Tenant-specific settings override
    settings = models.JSONField(
        default=dict,
        blank=True,
        help_text="Tenant-specific module settings"
    )

    # Enabled / disabled features (subset of module features)
    enabled_features = models.JSONField(
        default=list,
        blank=True,
        help_text="List of enabled feature flags"
    )
    disabled_features = models.JSONField(
        default=list,
        blank=True,
        help_text="List of explicitly disabled feature flags"
    )

    # Runtime usage stats
    usage_stats = models.JSONField(
        default=dict,
        blank=True,
        help_text="Runtime usage statistics for monitoring"
    )

    # Metadata
    metadata = models.JSONField(default=dict, blank=True)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        db_table = 'tenant_modules'
        unique_together = ['tenant', 'module']
        verbose_name = 'Tenant Module License'
        verbose_name_plural = 'Tenant Module Licenses'
    
    def __str__(self):
        return f"{self.tenant.name} - {self.module.display_name}"
    
    def is_active(self) -> bool:
        """Check if license is currently active."""
        if not self.is_enabled:
            return False
        if self.expires_at:
            from django.utils import timezone
            if self.expires_at < timezone.now():
                return False
        return True
    
    def days_remaining(self):
        """Get number of days remaining on license."""
        if not self.expires_at:
            return None
        from django.utils import timezone as tz
        delta = self.expires_at - tz.now()
        return max(delta.days, 0)

    def has_feature(self, feature_name: str) -> bool:
        """Check if a specific feature is enabled."""
        # If no features specified, all are enabled
        if not self.enabled_features:
            return True
        return feature_name in self.enabled_features


class Feature(models.Model):
    """
    Feature definition - represents a feature within a module.
    
    Features can be:
    - Enabled/disabled per tenant
    - Part of different license tiers
    - A/B tested
    """
    
    module = models.ForeignKey(
        Module,
        on_delete=models.CASCADE,
        related_name='features'
    )
    
    # Feature Information
    name = models.CharField(
        max_length=100,
        help_text="Feature identifier"
    )
    display_name = models.CharField(
        max_length=255,
        help_text="Human-readable name"
    )
    description = models.TextField(blank=True)
    
    # Availability
    is_enabled = models.BooleanField(
        default=True,
        help_text="Global feature toggle"
    )
    is_beta = models.BooleanField(
        default=False,
        help_text="Is this a beta feature?"
    )
    
    # License Requirement
    minimum_license = models.CharField(
        max_length=20,
        choices=LicenseType.choices,
        default=LicenseType.FREE,
        help_text="Minimum license type required for this feature"
    )
    
    # Rollout percentage (for gradual rollout)
    rollout_percentage = models.PositiveIntegerField(
        default=100,
        help_text="Percentage of tenants to enable this for (0-100)"
    )
    
    # Dependencies on other features
    depends_on = models.ManyToManyField(
        'self',
        symmetrical=False,
        blank=True,
        related_name='required_by'
    )
    
    # Configuration schema (JSON Schema for feature settings)
    config_schema = models.JSONField(
        default=dict,
        blank=True,
        help_text="JSON Schema for feature configuration"
    )
    
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        db_table = 'features'
        unique_together = ['module', 'name']
        verbose_name = 'Feature'
        verbose_name_plural = 'Features'
    
    def __str__(self):
        return f"{self.module.name}.{self.name}"


class TenantFeatureOverride(TenantAwareModel):
    """
    Tenant-specific feature override.
    
    Allows enabling/disabling features for specific tenants,
    regardless of global settings or license type.
    """
    
    feature = models.ForeignKey(
        Feature,
        on_delete=models.CASCADE,
        related_name='tenant_overrides'
    )
    
    # Override
    is_enabled = models.BooleanField(
        help_text="Override: is this feature enabled for this tenant?"
    )
    
    # Reason for override
    reason = models.TextField(
        blank=True,
        help_text="Reason for this override"
    )
    
    # Who made the override
    created_by = models.ForeignKey(
        'core_auth.User',
        on_delete=models.SET_NULL,
        null=True,
        blank=True
    )
    
    # Expiration (optional - for temporary overrides)
    expires_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When this override expires"
    )
    
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        db_table = 'tenant_feature_overrides'
        unique_together = ['tenant', 'feature']
        verbose_name = 'Tenant Feature Override'
        verbose_name_plural = 'Tenant Feature Overrides'
    
    def __str__(self):
        status = "enabled" if self.is_enabled else "disabled"
        return f"{self.tenant.name} - {self.feature} ({status})"
