from django.contrib.auth.models import AbstractUser, BaseUserManager
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.utils import timezone

class UserManager(BaseUserManager):
    """Define a model manager for User model with no username field."""

    use_in_migrations = True

    def _create_user(self, email, password, **extra_fields):
        """Create and save a User with the given email and password."""
        if not email:
            raise ValueError('The given email must be set')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, email, password=None, **extra_fields):
        """Create and save a regular User with the given email and password."""
        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(email, password, **extra_fields)

    def create_superuser(self, email, password, **extra_fields):
        """Create and save a SuperUser with the given email and password."""
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self._create_user(email, password, **extra_fields)

class Tenant(models.Model):
    name = models.CharField(max_length=255)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name

class User(AbstractUser):
    username = None
    email = models.EmailField(unique=True)
    tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, null=True, blank=True)
    role = models.CharField(max_length=100, blank=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = UserManager()

class BaseModel(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    is_deleted = models.BooleanField(default=False)
    deleted_at = models.DateTimeField(null=True, blank=True)
    created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='%(class)s_created_by')
    updated_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='%(class)s_updated_by')
    deleted_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='%(class)s_deleted_by')
    restored_at = models.DateTimeField(null=True, blank=True)
    restored_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='%(class)s_restored_by')


    class Meta:
        abstract = True

    def delete(self, user=None, *args, **kwargs):
        self.is_deleted = True
        self.deleted_at = timezone.now()
        if user:
            self.deleted_by = user
        self.save()
        ActivityLog.objects.create(
            actor=user,
            action=f'deleted a {self.__class__.__name__}',
            content_object=self,
            details={'id': self.id, 'name': str(self)}
        )

    def restore(self, user=None, *args, **kwargs):
        self.is_deleted = False
        self.deleted_at = None
        self.deleted_by = None
        self.restored_at = timezone.now()
        if user:
            self.restored_by = user
        self.save()
        ActivityLog.objects.create(
            actor=user,
            action=f'restored a {self.__class__.__name__}',
            content_object=self,
            details={'id': self.id, 'name': str(self)}
        )

class ActivityLog(models.Model):
    actor = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    action = models.CharField(max_length=255)
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')
    timestamp = models.DateTimeField(auto_now_add=True, db_index=True)
    details = models.JSONField(null=True, blank=True)

    class Meta:
        ordering = ['-timestamp']

    def get_action_badge(self):
        if 'deleted' in self.action:
            return ('bg-danger', 'deleted')
        elif 'restored' in self.action:
            return ('bg-success', 'restored')
        elif 'created' in self.action:
            return ('bg-primary', 'created')
        elif 'updated' in self.action:
            return ('bg-info', 'updated')
        else:
            action_verb = self.action.split(' ')[0]
            return ('bg-secondary', action_verb)

class Customer(BaseModel):
    STATUS_CHOICES = (
        ('active', 'Active'),
        ('inactive', 'Inactive'),
        ('lead', 'Lead'),
    )
    tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE)
    name = models.CharField(max_length=255)
    email = models.EmailField()
    phone = models.CharField(max_length=50, blank=True)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='active', db_index=True)
    owner = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='customers')

    class Meta:
        unique_together = ('tenant', 'email')
        indexes = [
            models.Index(fields=['tenant', 'status']),
            models.Index(fields=['created_at']),
        ]

    def __str__(self):
        return self.name

class Lead(BaseModel):
    STATUS_CHOICES = (
        ('new', 'New'),
        ('contacted', 'Contacted'),
        ('qualified', 'Qualified'),
        ('unqualified', 'Unqualified'),
    )
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='leads')
    source = models.CharField(max_length=255, blank=True)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='new', db_index=True)
    assigned_to = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='leads')

    def __str__(self):
        return f"Lead for {self.customer.name}"

class Opportunity(BaseModel):
    STAGE_CHOICES = (
        ('prospecting', 'Prospecting'),
        ('qualification', 'Qualification'),
        ('proposal', 'Proposal'),
        ('negotiation', 'Negotiation'),
        ('closed_won', 'Closed Won'),
        ('closed_lost', 'Closed Lost'),
    )
    name = models.CharField(max_length=255, blank=True, null=True)
    lead = models.ForeignKey(Lead, on_delete=models.CASCADE, related_name='opportunities')
    value = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    stage = models.CharField(max_length=20, choices=STAGE_CHOICES, default='prospecting', db_index=True)
    probability = models.FloatField(null=True, blank=True)
    close_date = models.DateField(null=True, blank=True)

    def __str__(self):
        return self.name

class ContactHistory(BaseModel):
    INTERACTION_CHOICES = (
        ('email', 'Email'),
        ('phone', 'Phone Call'),
        ('meeting', 'Meeting'),
        ('note', 'Note'),
    )
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='contact_history')
    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
    note = models.TextField()
    interaction_type = models.CharField(max_length=20, choices=INTERACTION_CHOICES, default='note')

    def __str__(self):
        return f"Contact with {self.customer.name} on {self.created_at.date()}"

class Note(BaseModel):
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')
    content = models.TextField()

    def __str__(self):
        return f"Note for {self.content_object}"