from django.db import models, transaction
from django.contrib.auth.models import User
from seniors.models import Senior


class VapiAssistant(models.Model):
    """Model for storing VAPI assistant IDs that can be managed by admins"""
    
    assistant_id = models.CharField(
        max_length=100,
        unique=True,
        help_text="The VAPI assistant ID (e.g., '7c0ac894-0739-48b9-a974-6131e5217d18')"
    )
    name = models.CharField(
        max_length=200,
        help_text="Human-readable name for this assistant (e.g., 'German Voice Assistant')"
    )
    is_active = models.BooleanField(
        default=True,
        help_text="Whether this assistant is available for users to select"
    )
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        ordering = ['-created_at']
        verbose_name = "VAPI Assistant"
        verbose_name_plural = "VAPI Assistants"
    
    def __str__(self):
        status = "Active" if self.is_active else "Inactive"
        return f"{self.name} ({status})"


class UserAssistantPreference(models.Model):
    """Model for storing user's preferred VAPI assistant"""
    
    user = models.OneToOneField(
        User,
        on_delete=models.CASCADE,
        related_name='assistant_preference',
        help_text="User who selected this assistant"
    )
    assistant = models.ForeignKey(
        VapiAssistant,
        on_delete=models.CASCADE,
        related_name='user_preferences',
        help_text="The selected VAPI assistant"
    )
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        verbose_name = "User Assistant Preference"
        verbose_name_plural = "User Assistant Preferences"
    
    def __str__(self):
        return f"{self.user.username} -> {self.assistant.name}"


class CallPrompt(models.Model):
    """Model for storing reusable call prompts that can be managed in admin"""
    
    name = models.CharField(
        max_length=200,
        help_text="A descriptive name for this prompt (e.g., 'General Check-in', 'Birthday Call')"
    )
    description = models.TextField(
        blank=True,
        help_text="Description of when and how to use this prompt"
    )
    prompt_template = models.TextField(
        help_text="The prompt template. Use {senior_name}, {senior_age}, {interests}, {health_notes}, {call_purpose}, and {conversation_context} as placeholders."
    )
    is_active = models.BooleanField(
        default=True,
        help_text="Whether this prompt is available for use"
    )
    is_default = models.BooleanField(
        default=False,
        help_text="Use this prompt as the default when no prompt is selected. Only one prompt can be default."
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    created_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='created_prompts',
        help_text="User who created this prompt"
    )
    
    class Meta:
        ordering = ['-created_at']
        verbose_name = "Call Prompt"
        verbose_name_plural = "Call Prompts"
        # Note: We handle the unique default constraint in code, not at database level
        # to avoid constraint violations during save operations
    
    def __str__(self):
        default_text = " (Default)" if self.is_default else ""
        return f"{self.name} ({'Active' if self.is_active else 'Inactive'}){default_text}"
    
    def save(self, *args, **kwargs):
        # If this prompt is being set as default, unset all other defaults first
        # This must happen BEFORE the save to avoid constraint violation
        if self.is_default:
            # Get the current PK before save (might be None for new objects)
            current_pk = self.pk
            
            # Unset all other defaults first - must happen before save()
            # This ensures only one default exists when the constraint is checked
            queryset = CallPrompt.objects.filter(is_default=True)
            if current_pk:
                queryset = queryset.exclude(pk=current_pk)
            # Execute the update immediately
            queryset.update(is_default=False)
        
        # Now save this object
        super().save(*args, **kwargs)


class Call(models.Model):
    """Model representing a call made to a senior"""
    
    STATUS_CHOICES = [
        ('initiated', 'Initiated'),
        ('ringing', 'Ringing'),
        ('answered', 'Answered'),
        ('completed', 'Completed'),
        ('failed', 'Failed'),
        ('busy', 'Busy'),
        ('no_answer', 'No Answer'),
        ('cancelled', 'Cancelled'),
    ]
    
    # Call Information
    senior = models.ForeignKey(
        Senior,
        on_delete=models.CASCADE,
        related_name='calls',
        help_text="The senior who received the call"
    )
    
    # Twilio Information
    twilio_sid = models.CharField(
        max_length=100,
        unique=True,
        null=True,
        blank=True,
        help_text="Twilio Call SID"
    )
    twilio_status = models.CharField(
        max_length=20,
        choices=STATUS_CHOICES,
        default='initiated',
        help_text="Status of the call"
    )
    
    # Call Details
    duration = models.PositiveIntegerField(
        null=True,
        blank=True,
        help_text="Call duration in seconds"
    )
    call_start_time = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When the call actually started"
    )
    call_end_time = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When the call ended"
    )
    
    # Vapi Information
    vapi_call_id = models.CharField(
        max_length=100,
        null=True,
        blank=True,
        help_text="Vapi.ai call ID"
    )
    vapi_assistant_id = models.CharField(
        max_length=100,
        null=True,
        blank=True,
        help_text="Vapi.ai assistant ID created for this call"
    )
    vapi_status = models.CharField(
        max_length=50,
        null=True,
        blank=True,
        help_text="Vapi.ai call status"
    )
    assistant = models.ForeignKey(
        VapiAssistant,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='calls',
        help_text="The VAPI assistant used for this call"
    )
    
    # Call Configuration
    prompt = models.ForeignKey(
        CallPrompt,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='calls',
        help_text="The prompt template selected for this call"
    )
    ai_prompt = models.TextField(
        blank=True,
        help_text="The AI prompt used for this call (includes memory context and prompt template)"
    )
    call_purpose = models.CharField(
        max_length=200,
        default='general_checkin',
        help_text="Purpose of the call (e.g., 'general_checkin', 'birthday_call')"
    )
    
    # Metadata
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    initiated_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        help_text="User who initiated the call"
    )

    is_limit_enforced = models.BooleanField(
        default=False,
        help_text="Whether the time limit enforcement (goodbye message) was triggered"
    )
    
    class Meta:
        ordering = ['-created_at']
    
    def __str__(self):
        return f"Call to {self.senior.name} - {self.twilio_status} ({self.created_at.strftime('%Y-%m-%d %H:%M')})"
    
    @property
    def status(self):
        """Return the current status of the call"""
        return self.twilio_status
    
    @property
    def is_successful(self):
        """Return True if the call was successful"""
        return self.twilio_status == 'completed'
    
    @property
    def formatted_duration(self):
        """Return formatted duration string"""
        if not self.duration:
            return "N/A"
        
        minutes = self.duration // 60
        seconds = self.duration % 60
        return f"{minutes}m {seconds}s"


class CallLog(models.Model):
    """Model for logging call events and status changes"""
    
    EVENT_TYPES = [
        ('initiated', 'Call Initiated'),
        ('twilio_created', 'Twilio Call Created'),
        ('vapi_started', 'Vapi Call Started'),
        ('answered', 'Call Answered'),
        ('completed', 'Call Completed'),
        ('failed', 'Call Failed'),
        ('status_changed', 'Status Changed'),
        ('webhook_received', 'Webhook Received'),
    ]
    
    call = models.ForeignKey(
        Call,
        on_delete=models.CASCADE,
        related_name='logs',
        help_text="The call this log entry belongs to"
    )
    
    event_type = models.CharField(
        max_length=20,
        choices=EVENT_TYPES,
        help_text="Type of event logged"
    )
    
    message = models.TextField(help_text="Log message")
    data = models.JSONField(
        default=dict,
        help_text="Additional data related to the event"
    )
    
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        ordering = ['-created_at']
    
    def __str__(self):
        return f"{self.call} - {self.event_type}: {self.message[:50]}"