"""
Platform Admin Models
Models for platform-level operations like tenant invitations
"""
import secrets
from datetime import timedelta
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.core.cache import cache


class PlatformSettings(models.Model):
    """
    Singleton model for platform-wide settings.
    Settings like Stripe keys can be overridden via environment variables.
    """

    # Stripe settings (can be overridden or set via admin)
    stripe_secret_key = models.CharField(
        max_length=255,
        blank=True,
        default='',
        help_text="Stripe secret key (overrides env if set)"
    )
    stripe_publishable_key = models.CharField(
        max_length=255,
        blank=True,
        default='',
        help_text="Stripe publishable key (overrides env if set)"
    )
    stripe_webhook_secret = models.CharField(
        max_length=255,
        blank=True,
        default='',
        help_text="Stripe webhook secret (overrides env if set)"
    )

    # Stripe validation info
    stripe_account_id = models.CharField(
        max_length=255,
        blank=True,
        default='',
        help_text="Stripe account ID (set after validation)"
    )
    stripe_account_name = models.CharField(
        max_length=255,
        blank=True,
        default='',
        help_text="Stripe account name (set after validation)"
    )
    stripe_keys_validated_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When the Stripe keys were last validated"
    )
    stripe_validation_error = models.TextField(
        blank=True,
        default='',
        help_text="Last validation error, if any"
    )

    # OAuth settings - stored as JSON for flexibility
    oauth_settings = models.JSONField(
        default=dict,
        blank=True,
        help_text="OAuth provider settings (Google, Apple, etc.)"
    )
    # Example oauth_settings structure:
    # {
    #   "allow_registration": true,
    #   "google": {"enabled": true, "client_id": "...", "client_secret": "..."},
    #   "apple": {"enabled": false, "client_id": "", ...},
    #   ...
    # }

    # Email settings
    email_check_interval_minutes = models.PositiveIntegerField(
        default=5,
        help_text="How often to check for new incoming emails (in minutes)"
    )

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

    class Meta:
        app_label = 'platform_admin'
        verbose_name = 'Platform Settings'
        verbose_name_plural = 'Platform Settings'

    def __str__(self):
        return "Platform Settings"

    def save(self, *args, **kwargs):
        # Ensure only one instance exists
        self.pk = 1
        super().save(*args, **kwargs)
        # Clear cache
        cache.delete('platform_settings')

    def delete(self, *args, **kwargs):
        # Prevent deletion
        pass

    @classmethod
    def get_instance(cls):
        """Get or create the singleton instance"""
        # Try cache first
        cached = cache.get('platform_settings')
        if cached:
            return cached

        instance, _ = cls.objects.get_or_create(pk=1)
        cache.set('platform_settings', instance, timeout=300)  # 5 min cache
        return instance

    def get_stripe_secret_key(self):
        """Get Stripe secret key (database or env)"""
        from django.conf import settings
        if self.stripe_secret_key:
            return self.stripe_secret_key
        return getattr(settings, 'STRIPE_SECRET_KEY', '')

    def get_stripe_publishable_key(self):
        """Get Stripe publishable key (database or env)"""
        from django.conf import settings
        if self.stripe_publishable_key:
            return self.stripe_publishable_key
        return getattr(settings, 'STRIPE_PUBLISHABLE_KEY', '')

    def get_stripe_webhook_secret(self):
        """Get Stripe webhook secret (database or env)"""
        from django.conf import settings
        if self.stripe_webhook_secret:
            return self.stripe_webhook_secret
        return getattr(settings, 'STRIPE_WEBHOOK_SECRET', '')

    def has_stripe_keys(self):
        """Check if Stripe keys are configured"""
        return bool(self.get_stripe_secret_key() and self.get_stripe_publishable_key())

    def stripe_keys_from_env(self):
        """Check if Stripe keys come from environment"""
        from django.conf import settings
        return (
            not self.stripe_secret_key and
            bool(getattr(settings, 'STRIPE_SECRET_KEY', ''))
        )

    def mask_key(self, key, visible_chars=8):
        """Mask a key, showing only first/last chars"""
        if not key:
            return ''
        if len(key) <= visible_chars * 2:
            return '*' * len(key)
        return f"{key[:visible_chars]}...{key[-4:]}"


class SubscriptionPlan(models.Model):
    """
    Subscription plans that can be assigned to tenants.
    Links to Stripe products/prices for billing.
    """

    class PlanType(models.TextChoices):
        BASE = 'base', _('Base Plan')
        ADDON = 'addon', _('Add-on')

    name = models.CharField(max_length=100)
    description = models.TextField(blank=True, default='')
    plan_type = models.CharField(
        max_length=10,
        choices=PlanType.choices,
        default=PlanType.BASE
    )

    # Stripe integration
    stripe_product_id = models.CharField(
        max_length=255,
        blank=True,
        default='',
        help_text="Stripe Product ID"
    )
    stripe_price_id = models.CharField(
        max_length=255,
        blank=True,
        default='',
        help_text="Stripe Price ID (for monthly billing)"
    )

    # Pricing
    price_monthly = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        null=True,
        blank=True,
        help_text="Monthly price in dollars"
    )
    price_yearly = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        null=True,
        blank=True,
        help_text="Yearly price in dollars"
    )

    # Features included (stored as JSON array of strings)
    features = models.JSONField(
        default=list,
        blank=True,
        help_text="List of feature descriptions"
    )

    # Platform permissions (what features this plan grants)
    permissions = models.JSONField(
        default=dict,
        blank=True,
        help_text="Platform permissions to grant (e.g., can_accept_payments, can_use_custom_domain)"
    )

    # Feature limits (what capabilities this plan has)
    limits = models.JSONField(
        default=dict,
        blank=True,
        help_text="Feature limits and capabilities to grant (e.g. max_users, max_resources)"
    )

    # Transaction fees for payment processing
    transaction_fee_percent = models.DecimalField(
        max_digits=5,
        decimal_places=2,
        default=2.9,
        help_text="Transaction fee percentage"
    )
    transaction_fee_fixed = models.DecimalField(
        max_digits=5,
        decimal_places=2,
        default=0.30,
        help_text="Fixed transaction fee in dollars"
    )

    # SMS & Communication Settings
    sms_enabled = models.BooleanField(
        default=False,
        help_text="Whether SMS reminders are available for this tier"
    )
    sms_price_per_message_cents = models.IntegerField(
        default=3,  # $0.03
        help_text="Price per SMS message in cents"
    )

    # Masked Calling Settings
    masked_calling_enabled = models.BooleanField(
        default=False,
        help_text="Whether masked calling is available for this tier"
    )
    masked_calling_price_per_minute_cents = models.IntegerField(
        default=5,  # $0.05
        help_text="Price per voice minute in cents"
    )

    # Proxy Phone Number Settings
    proxy_number_enabled = models.BooleanField(
        default=False,
        help_text="Whether tenants can have dedicated proxy numbers"
    )
    proxy_number_monthly_fee_cents = models.IntegerField(
        default=200,  # $2.00
        help_text="Monthly fee per proxy number in cents"
    )

    # Contracts Feature
    contracts_enabled = models.BooleanField(
        default=False,
        help_text="Whether tenants can use the contracts feature"
    )

    # Default Credit Settings (for new tenants on this tier)
    default_auto_reload_enabled = models.BooleanField(
        default=False,
        help_text="Whether auto-reload is enabled by default for new tenants"
    )
    default_auto_reload_threshold_cents = models.IntegerField(
        default=1000,  # $10
        help_text="Default auto-reload threshold in cents"
    )
    default_auto_reload_amount_cents = models.IntegerField(
        default=2500,  # $25
        help_text="Default auto-reload amount in cents"
    )

    # Visibility
    is_active = models.BooleanField(default=True)
    is_public = models.BooleanField(
        default=True,
        help_text="Whether this plan is visible on public pricing page"
    )
    is_most_popular = models.BooleanField(
        default=False,
        help_text="Whether to highlight this plan as the most popular choice"
    )
    show_price = models.BooleanField(
        default=True,
        help_text="Whether to display the price on the marketing site (disable for 'Contact Us')"
    )

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

    class Meta:
        app_label = 'platform_admin'
        ordering = ['price_monthly', 'name']

    def __str__(self):
        return f"{self.name} ({self.get_plan_type_display()})"


class TenantInvitation(models.Model):
    """
    Invitation for new business owners to create their tenant.
    Allows platform admins to pre-configure custom limits and permissions.

    Flow:
    1. Platform admin creates invitation with email and custom settings
    2. System sends email with unique token link
    3. Invitee clicks link, completes onboarding wizard
    4. Tenant, domain, and owner user are created with pre-configured settings
    """

    class Status(models.TextChoices):
        PENDING = 'PENDING', _('Pending')
        ACCEPTED = 'ACCEPTED', _('Accepted')
        EXPIRED = 'EXPIRED', _('Expired')
        CANCELLED = 'CANCELLED', _('Cancelled')

    # Invitation target
    email = models.EmailField(help_text="Email address to send invitation to")
    token = models.CharField(max_length=64, unique=True)
    status = models.CharField(
        max_length=20,
        choices=Status.choices,
        default=Status.PENDING
    )

    # Pre-configured business settings (owner can modify during onboarding)
    suggested_business_name = models.CharField(
        max_length=100,
        blank=True,
        help_text="Suggested business name (owner can change during onboarding)"
    )

    # Subscription settings
    subscription_tier = models.CharField(
        max_length=50,
        choices=[
            ('FREE', 'Free Trial'),
            ('STARTER', 'Starter'),
            ('PROFESSIONAL', 'Professional'),
            ('ENTERPRISE', 'Enterprise'),
        ],
        default='PROFESSIONAL'
    )

    # Custom limits (null = use tier defaults)
    custom_max_users = models.IntegerField(
        null=True,
        blank=True,
        help_text="Custom max users limit (null = use tier default)"
    )
    custom_max_resources = models.IntegerField(
        null=True,
        blank=True,
        help_text="Custom max resources limit (null = use tier default)"
    )

    # Platform permissions (what features this tenant can access)
    # These are special permissions not available in normal tier packages
    permissions = models.JSONField(
        default=dict,
        blank=True,
        help_text="Platform permissions to grant (e.g., can_accept_payments, can_use_custom_domain)"
    )
    # Example permissions structure:
    # {
    #   "can_manage_oauth_credentials": true,
    #   "can_accept_payments": true,
    #   "can_use_custom_domain": true,
    #   "can_white_label": false,
    #   "can_api_access": true,
    # }

    # Feature limits (what capabilities this tenant has)
    limits = models.JSONField(
        default=dict,
        blank=True,
        help_text="Feature limits and capabilities to grant"
    )
    # Example limits structure:
    # {
    #   "can_add_video_conferencing": true,
    #   "max_event_types": 10,                # null = unlimited
    #   "max_calendars_connected": 5,         # null = unlimited
    #   "can_connect_to_api": true,
    #   "can_book_repeated_events": true,
    #   "can_require_2fa": true,
    #   "can_download_logs": false,
    #   "can_delete_data": false,
    #   "can_use_masked_phone_numbers": false,
    #   "can_use_pos": false,
    #   "can_use_mobile_app": true,
    # }

    # Personal message to include in email
    personal_message = models.TextField(
        blank=True,
        help_text="Optional personal message to include in the invitation email"
    )

    # Metadata
    invited_by = models.ForeignKey(
        'users.User',
        on_delete=models.SET_NULL,
        null=True,
        related_name='tenant_invitations_sent',
        help_text="Platform admin who sent the invitation"
    )

    # Timestamps
    created_at = models.DateTimeField(auto_now_add=True)
    expires_at = models.DateTimeField()
    accepted_at = models.DateTimeField(null=True, blank=True)

    # Links to created resources (after acceptance)
    created_tenant = models.ForeignKey(
        'core.Tenant',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='invitation',
        help_text="Tenant created when invitation was accepted"
    )
    created_user = models.ForeignKey(
        'users.User',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='tenant_invitation_accepted',
        help_text="Owner user created when invitation was accepted"
    )

    class Meta:
        app_label = 'platform_admin'
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['token']),
            models.Index(fields=['email', 'status']),
            models.Index(fields=['status', 'expires_at']),
        ]

    def __str__(self):
        return f"Tenant invitation for {self.email} ({self.get_status_display()})"

    def save(self, *args, **kwargs):
        if not self.token:
            self.token = secrets.token_urlsafe(32)
        if not self.expires_at:
            # Default expiration: 7 days
            self.expires_at = timezone.now() + timedelta(days=7)
        super().save(*args, **kwargs)

    def is_valid(self):
        """Check if invitation can still be accepted"""
        if self.status != self.Status.PENDING:
            return False
        if timezone.now() > self.expires_at:
            return False
        return True

    def accept(self, tenant, user):
        """Mark invitation as accepted and link to created resources"""
        self.status = self.Status.ACCEPTED
        self.accepted_at = timezone.now()
        self.created_tenant = tenant
        self.created_user = user
        self.save()

    def cancel(self):
        """Cancel a pending invitation"""
        if self.status == self.Status.PENDING:
            self.status = self.Status.CANCELLED
            self.save()

    def get_effective_max_users(self):
        """Get max users (custom or tier default)"""
        if self.custom_max_users is not None:
            return self.custom_max_users
        # Tier defaults
        tier_defaults = {
            'FREE': 2,
            'STARTER': 5,
            'PROFESSIONAL': 15,
            'ENTERPRISE': 50,
        }
        return tier_defaults.get(self.subscription_tier, 5)

    def get_effective_max_resources(self):
        """Get max resources (custom or tier default)"""
        if self.custom_max_resources is not None:
            return self.custom_max_resources
        # Tier defaults
        tier_defaults = {
            'FREE': 3,
            'STARTER': 10,
            'PROFESSIONAL': 30,
            'ENTERPRISE': 100,
        }
        return tier_defaults.get(self.subscription_tier, 10)

    @classmethod
    def create_invitation(cls, email, invited_by, subscription_tier='PROFESSIONAL',
                          suggested_business_name='', custom_max_users=None,
                          custom_max_resources=None, permissions=None, limits=None,
                          personal_message=''):
        """
        Create a new tenant invitation, cancelling any existing pending invitations
        for the same email.
        """
        # Cancel existing pending invitations for this email
        cls.objects.filter(
            email=email,
            status=cls.Status.PENDING
        ).update(status=cls.Status.CANCELLED)

        # Create new invitation
        return cls.objects.create(
            email=email,
            invited_by=invited_by,
            subscription_tier=subscription_tier,
            suggested_business_name=suggested_business_name,
            custom_max_users=custom_max_users,
            custom_max_resources=custom_max_resources,
            permissions=permissions or {},
            limits=limits or {},
            personal_message=personal_message,
        )


class PlatformEmailAddress(models.Model):
    """
    Platform-managed email addresses hosted on mail.talova.net.
    These are managed directly via SSH/Docker commands on the mail server.

    Unlike TicketEmailAddress which supports arbitrary IMAP/SMTP servers,
    this model is specifically for platform email addresses managed on our
    dedicated mail server.
    """

    class Domain(models.TextChoices):
        SMOOTHSCHEDULE = 'smoothschedule.com', 'smoothschedule.com'
        TALOVA = 'talova.net', 'talova.net'

    # Display information
    display_name = models.CharField(
        max_length=100,
        help_text="Display name (e.g., 'Support', 'Billing', 'Sales')"
    )
    local_part = models.CharField(
        max_length=64,
        help_text="Local part of email address (before @)"
    )
    domain = models.CharField(
        max_length=50,
        choices=Domain.choices,
        default=Domain.SMOOTHSCHEDULE,
        help_text="Email domain"
    )
    color = models.CharField(
        max_length=7,
        default='#3b82f6',
        help_text="Hex color code for visual identification"
    )
    sender_name = models.CharField(
        max_length=100,
        blank=True,
        default='',
        help_text="Name to show in From header (e.g., 'SmoothSchedule Support'). If blank, uses display_name."
    )
    assigned_user = models.ForeignKey(
        'users.User',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='platform_email_addresses',
        help_text="User associated with this email. If set, their name is used as sender name."
    )

    # Account credentials (stored securely, synced to mail server)
    password = models.CharField(
        max_length=255,
        help_text="Password for the email account (stored encrypted, synced to mail server)"
    )

    # Status
    is_active = models.BooleanField(
        default=True,
        help_text="Whether this email address is active"
    )
    is_default = models.BooleanField(
        default=False,
        help_text="Default email for platform support"
    )

    # Mail server sync status
    mail_server_synced = models.BooleanField(
        default=False,
        help_text="Whether the account exists on the mail server"
    )
    last_sync_error = models.TextField(
        blank=True,
        default='',
        help_text="Last sync error message, if any"
    )
    last_synced_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When this account was last synced to the mail server"
    )

    # Usage tracking
    emails_processed_count = models.IntegerField(
        default=0,
        help_text="Total number of emails processed for this address"
    )
    last_check_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When emails were last checked for this address"
    )

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

    class Meta:
        app_label = 'platform_admin'
        ordering = ['-is_default', 'display_name']
        unique_together = [['local_part', 'domain']]
        verbose_name = 'Platform Email Address'
        verbose_name_plural = 'Platform Email Addresses'

    def __str__(self):
        return f"{self.display_name} <{self.email_address}>"

    @property
    def email_address(self):
        """Full email address."""
        return f"{self.local_part}@{self.domain}"

    @property
    def effective_sender_name(self):
        """
        Name to use in From header.
        Priority: assigned_user's full name > sender_name > display_name
        """
        if self.assigned_user:
            user_name = self.assigned_user.get_full_name()
            if user_name:
                return user_name
        if self.sender_name:
            return self.sender_name
        return self.display_name

    def save(self, *args, **kwargs):
        # Ensure only one default
        if self.is_default:
            PlatformEmailAddress.objects.filter(
                is_default=True
            ).exclude(pk=self.pk).update(is_default=False)
        super().save(*args, **kwargs)

    # Pre-configured mail server settings
    MAIL_SERVER_HOST = 'mail.talova.net'
    IMAP_HOST = 'mail.talova.net'
    IMAP_PORT = 993
    IMAP_USE_SSL = True
    SMTP_HOST = 'mail.talova.net'
    SMTP_PORT = 587
    SMTP_USE_TLS = True
    SMTP_USE_SSL = False

    def get_imap_settings(self):
        """Get IMAP connection settings."""
        return {
            'host': self.IMAP_HOST,
            'port': self.IMAP_PORT,
            'use_ssl': self.IMAP_USE_SSL,
            'username': self.email_address,
            'password': self.password,
            'folder': 'INBOX',
        }

    def get_smtp_settings(self):
        """Get SMTP connection settings."""
        return {
            'host': self.SMTP_HOST,
            'port': self.SMTP_PORT,
            'use_tls': self.SMTP_USE_TLS,
            'use_ssl': self.SMTP_USE_SSL,
            'username': self.email_address,
            'password': self.password,
        }
