from django.db import models
from django.conf import settings
from django.utils.translation import gettext_lazy as _

from apps.core.models import BaseModel
from apps.accounts.models import User

# Define choices for different action types using Django's TextChoices.
class ActionType(models.TextChoices):
    """Choices for different action types."""
    ADD = "ADD", "Add an object"
    UPDATE = "UPDATE", "Update an object"
    DELETE = "DELETE", "Delete an object"
    VIEW = "VIEW", "View an object"
    SEARCH = "SEARCH", "Search for an object"
    DOWNLOAD = "DOWNLOAD", "Download an object"
    UPLOAD = "UPLOAD", "Upload an object"
    APPROVE = "APPROVE", "Approve an object"
    REJECT = "REJECT", "Reject an object"
    COMMENT = "COMMENT", "Comment on an object"
    SHARE = "SHARE", "Share an object"
    ARCHIVE = "ARCHIVE", "Archive an object"
    RESTORE = "RESTORE", "Restore an object"
    CREATE = "CREATE", "Create an object"
    READ = "READ", "Read an object"
    WRITE = "WRITE", "Write an object"
    CONFIGURE = "CONFIGURE", "Configure settings"
    ACTIVATE = "ACTIVATE", "Activate an object"
    DEACTIVATE = "DEACTIVATE", "Deactivate an object"
    SUBMIT = "SUBMIT", "Submit an object"
    CANCEL = "CANCEL", "Cancel an action or object"
    REFRESH = "REFRESH", "Refresh data or object"
    ASSIGN = "ASSIGN", "Assign an object to a user"
    UNASSIGN = "UNASSIGN", "Unassign an object from a user" 
    APPROVE_REQUEST = "APPROVE_REQUEST", "Approve a request"
    REJECT_REQUEST = "REJECT_REQUEST", "Reject a request"
    NOTIFY = "NOTIFY", "Send a notification"
    CONFIRM = "CONFIRM", "Confirm an action"
    UNDO = "UNDO", "Undo an action"
    REDO = "REDO", "Redo an action"
    EXPORT = "EXPORT", "Export data or object"
    IMPORT = "IMPORT", "Import data or object"
    SYNC = "SYNC", "Synchronize data or object"

# Model to represent user activities and associated actions.
class Activity(BaseModel):
    """
    Represents user activities and their associated actions.

    Attributes:
        user (ForeignKey): Reference to the user performing the action.
        timestamp (DateTimeField): Timestamp of when the activity occurred.
        action_type (CharField): Type of action performed (ADD, UPDATE, DELETE).
        details (TextField, optional): Additional details or context for the activity.
        related_object_id (CharField, optional): ID of the related object, if applicable.
        related_object_type (CharField, optional): Type or model of the related object, if applicable.

    Meta:
        ordering: Default ordering based on timestamp in descending order.
    """

    # Reference to the user model for the ForeignKey relationship.
    performer = models.ForeignKey(
        User,
        on_delete=models.CASCADE,  # Cascade delete behavior when related user is deleted.
        verbose_name="User",  # Human-readable name for the field in admin interface.
        help_text="The user who performed the activity."  # Additional help text for field in admin interface.
    ) 
    # Timestamp for when the activity is logged, set automatically upon creation.
    timestamp = models.DateTimeField(
        auto_now_add=True,  # Automatically set the field to now when the object is first created.
        verbose_name="Timestamp",  # Human-readable name for the field in admin interface.
        help_text="The timestamp when the activity was logged."  # Additional help text for field in admin interface.
    ) 
    # Type of action performed by the user, with predefined choices.
    action_type = models.CharField(
        max_length=20,
        choices=ActionType.choices,  # Available choices from ActionType class.
        verbose_name="Action Type",  # Human-readable name for the field in admin interface.
        help_text="Type of action performed by the user."  # Additional help text for field in admin interface.
    ) 
    # Additional details or context for the activity, optional.
    details = models.TextField(
        blank=True,
        null=True,
        verbose_name="Details",  # Human-readable name for the field in admin interface.
        help_text="Additional details or context for the activity."  # Additional help text for field in admin interface.
    ) 
    # ID of the related object, if applicable, optional.
    related_object_id = models.CharField(
        blank=True,
        null=True,
        max_length=64,
        verbose_name="Related Object ID",  # Human-readable name for the field in admin interface.
        help_text="ID of the related object, if applicable."  # Additional help text for field in admin interface.
    ) 
    # Type or model of the related object, if applicable, optional.
    related_object_type = models.CharField(
        max_length=50,
        blank=True,
        null=True,
        verbose_name="Related Object Type",  # Human-readable name for the field in admin interface.
        help_text="Type or model of the related object, if applicable."  # Additional help text for field in admin interface.
    )

    # Meta class to specify model-level metadata.
    class Meta:
        verbose_name = "Activity"  # Singular name for the model in admin interface.
        verbose_name_plural = "Activities"  # Plural name for the model in admin interface.
        ordering = ["-timestamp"]  # Default ordering of records based on timestamp in descending order.

    # String representation of the Activity model instance.
    def __str__(self):
        """String representation of the Activity model instance."""
        return f"{self.user.email} - {self.action_type}"  # Display user email and action type as string.

class ActivityLog(BaseModel):
    """Model for logging user and system activities.
    
    This model provides a centralized way to track activities
    across the application for auditing and monitoring.
    """
    
    ACTIVITY_TYPES = [
        # CRUD Operations
        ('create', _('Create')),
        ('read', _('Read')),
        ('update', _('Update')),
        ('delete', _('Delete')),
        ('view', _('View')),
        
        # Authentication
        ('login', _('Login')),
        ('logout', _('Logout')),
        
        # Data Operations
        ('export', _('Export')),
        ('import', _('Import')),
        ('download', _('Download')),
        ('upload', _('Upload')),
        
        # System Events
        ('system', _('System')),
        ('error', _('Error')),
        ('warning', _('Warning')),
        ('info', _('Info')), 
    ]
    
    user = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        help_text=_('User who performed the activity')
    )
    
    activity_type = models.CharField(
        _('Activity Type'),
        max_length=20,
        choices=ACTIVITY_TYPES,
        help_text=_('Type of activity performed')
    )
    
    object_type = models.CharField(
        _('Object Type'),
        max_length=100,
        blank=True,
        help_text=_('Type of object affected by the activity')
    )
    
    object_id = models.CharField(
        _('Object ID'),
        max_length=100,
        blank=True,
        help_text=_('ID of the object affected by the activity')
    )
    
    description = models.TextField(
        _('Description'),
        help_text=_('Description of the activity')
    )
    
    ip_address = models.GenericIPAddressField(
        _('IP Address'),
        null=True,
        blank=True,
        help_text=_('IP address from which the activity was performed')
    )
    
    user_agent = models.TextField(
        _('User Agent'),
        blank=True,
        help_text=_('User agent string of the client')
    )
    
    extra_data = models.JSONField(
        _('Extra Data'),
        default=dict,
        blank=True,
        help_text=_('Additional data related to the activity')
    )
    
    class Meta:
        verbose_name = _('Activity Log')
        verbose_name_plural = _('Activity Logs')
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['user', 'activity_type']),
            models.Index(fields=['object_type', 'object_id']),
            models.Index(fields=['created_at']),
        ]
    
    def __str__(self):
        user_str = self.user.username if self.user else 'System'
        return f"{user_str} - {self.activity_type} - {self.description[:50]}"
    
    @classmethod
    def log_activity(cls, user, activity_type, description, object_type=None, 
                    object_id=None, ip_address=None, user_agent=None, extra_data=None):
        """Create an activity log entry."""
        return cls.objects.create(
            user=user,
            activity_type=activity_type,
            description=description,
            object_type=object_type,
            object_id=object_id,
            ip_address=ip_address,
            user_agent=user_agent,
            extra_data=extra_data or {}
        )
