from django.db import models
from django.contrib.auth.models import AbstractBaseUser,BaseUserManager,PermissionsMixin, AbstractUser
from django.core.exceptions import ValidationError
from django.db.models import Sum
from django.core.validators import MaxValueValidator, MinValueValidator
from django.utils.translation import gettext_lazy as _
from src.manager import AccountManager
from PIL import Image
from io import BytesIO
from django.core.files.uploadedfile import InMemoryUploadedFile
import sys, os

# Create your models here.

class UserAccount(AbstractBaseUser,PermissionsMixin):

    email         = models.EmailField(('email address'),max_length=150,unique=True, null=False)
    username      = models.CharField(max_length=255,unique=True, blank=True, null=True)

    fullname     = models.CharField(max_length=255,null=True, blank=True)

    birthday = models.DateField( verbose_name='date of birth',null=True, blank=True)
    tel          = models.fields.CharField(null=False, max_length=255, verbose_name="Telephone number" , default="")
    adress          = models.fields.CharField(null=False, max_length=255, verbose_name="Adress", default="")

    Gend = [
    ('Male', 'Male'),
    ('Female', 'Female'),
    ('Other', 'Other'),
    ]

    gender = models.fields.CharField(
        max_length=20,
        choices=Gend,
        default='Male',
    )
    picture = models.fields.CharField(null=True, max_length=255, verbose_name="Picture", blank=True)
    type = [
    ('users', 'users'),
    ('personnel', 'personnel'),
    ('staff', 'Staff'),
    ]

    typecompte = models.fields.CharField(
        max_length=50,
        choices=type,
        default='users',
    )

    date_joined   = models.DateTimeField(verbose_name='date_joined',auto_now_add=True)
    last_login    = models.DateTimeField(verbose_name='last login',auto_now=True)
    is_admin      = models.BooleanField(default=False)
    is_active     = models.BooleanField(default=True)
    is_staff      = models.BooleanField(default=False)
    is_superuser  = models.BooleanField(default=False)

    objects = AccountManager()
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['tel']

    def __str__(self):
        return self.fullname

class ContactMessage(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField()
    subject = models.CharField(max_length=200)
    message = models.TextField(blank=True, null=True)
    sent_at = models.DateTimeField(auto_now_add=True)
    recieption = models.BooleanField(default=True)

    def __str__(self):
        return f"{self.name} - {self.subject}"
    
class tb_actualitenews(models.Model):
    name = models.CharField(max_length=100)
    date = models.EmailField()
    title = models.CharField(max_length=200)
    shortdes = models.TextField(blank=True, null=True)
    longdes = models.TextField(blank=True, null=True)
    regdate = models.DateTimeField(auto_now_add=True)
    update = models.DateTimeField(auto_now_add=True)
    status = models.BooleanField(default=True)

    def __str__(self):
        return f"{self.name} - {self.title}"
    
class tb_eventcate(models.Model):
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=400)
    title = models.CharField(max_length=250,null=True, blank=True)
    picture = models.ImageField(upload_to="pictures/", null=True, verbose_name="Picturent", blank=True)
    regdate = models.DateTimeField(auto_now_add=True)
    update = models.DateTimeField(auto_now_add=True)
    status = models.BooleanField(default=True)

    def __str__(self):
        return f"{self.name} - {self.title}"
    
class dashboardpicture(models.Model):
    textdisplay1     = models.CharField(max_length=255,null=True, blank=True)
    textdisplay2     = models.CharField(max_length=255,null=True, blank=True)
    textdisplay3     = models.CharField(max_length=255,null=True, blank=True)
    picture = models.ImageField(upload_to="pictures/", null=True, verbose_name="Picture", blank=True)
    f_active = models.BooleanField(default=True)
    his_registration_date   = models.DateTimeField(auto_now_add=True, null=True, blank=True)
    his_update_date   = models.DateTimeField(auto_now_add=True, null=True, blank=True)
    his_delete_date   = models.DateTimeField(auto_now_add=True, null=True, blank=True)
    userid         = models.ForeignKey(UserAccount,related_name='useriddash',  null=True, blank=True, on_delete=models.SET_NULL)
    update_userid         = models.ForeignKey(UserAccount,related_name='updauseriddash',  null=True, blank=True, on_delete=models.SET_NULL)
    delete_userid         = models.ForeignKey(UserAccount,related_name='deluseriddash', null=True, blank=True, on_delete=models.SET_NULL)
    rank    = models.IntegerField(null=True, blank=True,  default=0)
    def __str__(self):
        return f'{self.textdisplay1}'
    
class tb_eventpostupdate(models.Model):
    reportername  = models.CharField(max_length=255,null=True, blank=True)
    projectname     = models.CharField(max_length=255,null=True, blank=True)
    category = models.ForeignKey(tb_eventcate, on_delete=models.SET_NULL, null=True, blank=True, related_name='cateprojects')
    title     = models.CharField(max_length=255,null=True, blank=True)
    date = models.DateField(null=True, blank=True)
    textdisplay1     = models.TextField(blank=True, null=True)
    textdisplay2     = models.TextField(blank=True, null=True)
    textdisplay3     = models.TextField(blank=True, null=True)
    textdisplay4     = models.TextField(blank=True, null=True)
    displaypic = models.ImageField(upload_to="pictures/", null=True, verbose_name="Picture", blank=True)
    picture1 = models.ImageField(upload_to="pictures/", null=True, verbose_name="Picture1", blank=True)
    picture2 = models.ImageField(upload_to="pictures/", null=True, verbose_name="Picture2", blank=True)
    picture3 = models.ImageField(upload_to="pictures/", null=True, verbose_name="Picture3", blank=True)
    picture4 = models.ImageField(upload_to="pictures/", null=True, verbose_name="Picture4", blank=True)
    picture5 = models.ImageField(upload_to="pictures/", null=True, verbose_name="Picture5", blank=True)
    f_active = models.BooleanField(default=True)
    his_registration_date   = models.DateTimeField(auto_now_add=True, null=True, blank=True)
    his_update_date   = models.DateTimeField(auto_now_add=True, null=True, blank=True)
    his_delete_date   = models.DateTimeField(auto_now_add=True, null=True, blank=True)
    userid         = models.ForeignKey('UserLogin',related_name='useriddash1',  null=True, blank=True, on_delete=models.SET_NULL)
    update_userid         = models.ForeignKey('UserLogin',related_name='updauseriddash2',  null=True, blank=True, on_delete=models.SET_NULL)
    delete_userid         = models.ForeignKey('UserLogin',related_name='deluseriddash3', null=True, blank=True, on_delete=models.SET_NULL)
    rank    = models.IntegerField(null=True, blank=True,  default=0)
    def __str__(self):
        return f'{self.textdisplay1}'
    

class UserLogin(models.Model):
    userid = models.CharField(max_length=50, unique=True)
    password = models.CharField(max_length=128)  # Store hashed password in production
    name = models.CharField(max_length=100)
    surname = models.CharField(max_length=100)
    dateofbirth = models.DateField(null=True, blank=True)
    id_number = models.CharField(max_length=20)
    is_active = models.BooleanField(default=True)
    role = models.CharField(max_length=50, null=True, blank=True)
    registered_on = models.DateTimeField(auto_now_add=True)



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

class tb_teams(models.Model):
    position  = models.CharField(max_length=255,null=True, blank=True)
    department  = models.CharField(max_length=255,null=True, blank=True)
    staffname     = models.CharField(max_length=255,null=True, blank=True)
    staffsurname     = models.CharField(max_length=255,null=True, blank=True)
    staffmiddlename = models.CharField(max_length=255,null=True, blank=True)
    office     = models.CharField(max_length=255,null=True, blank=True)
    address = models.CharField(max_length=255,null=True, blank=True)
    region = models.CharField(max_length=255,null=True, blank=True)
    dob = models.DateField(null=True, blank=True)
    datejoin = models.DateField(null=True, blank=True)
    textdisplay1     = models.TextField(blank=True, null=True)
    textdisplay2     = models.TextField(blank=True, null=True)
    textdisplay3     = models.TextField(blank=True, null=True)
    textdisplay4    = models.TextField(blank=True, null=True)
    textdisplay5     = models.TextField(blank=True, null=True)
    dp = models.ImageField(upload_to="pictures/", null=True, verbose_name="Picture", blank=True)
    picture1 = models.ImageField(upload_to="pictures/", null=True, verbose_name="Picture1", blank=True)
    picture2 = models.ImageField(upload_to="pictures/", null=True, verbose_name="Picture2", blank=True)
    picture3 = models.ImageField(upload_to="pictures/", null=True, verbose_name="Picture3", blank=True)
    f_active = models.BooleanField(default=True)
    his_registration_date   = models.DateTimeField(auto_now_add=True, null=True, blank=True)
    his_update_date   = models.DateTimeField(auto_now_add=True, null=True, blank=True)
    his_delete_date   = models.DateTimeField(auto_now_add=True, null=True, blank=True)
    userid         = models.ForeignKey(UserLogin,related_name='useriddash2',  null=True, blank=True, on_delete=models.SET_NULL)
    update_userid         = models.ForeignKey(UserLogin,related_name='updauseriddash4',  null=True, blank=True, on_delete=models.SET_NULL)
    delete_userid         = models.ForeignKey(UserLogin,related_name='deluseriddash4', null=True, blank=True, on_delete=models.SET_NULL)
    rank    = models.IntegerField(null=True, blank=True,  default=0)
    def __str__(self):
        return f'{self.textdisplay1}'

#Payments models start

def validate_image_file_extension(value):
    valid_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp']
    ext = os.path.splitext(value.name)[1].lower()
    if ext not in valid_extensions:
        raise ValidationError('Unsupported file extension.')

def validate_image_file_size(value):
    filesize = value.size
    if filesize > 5 * 1024 * 1024:  # 5MB limit
        raise ValidationError("The maximum file size that can be uploaded is 5MB")

class ProjectType(models.Model):
    name = models.CharField(max_length=100, unique=True)
    description = models.TextField(blank=True, null=True)
    image = models.ImageField(
        upload_to='project_types/',
        null=True,
        blank=True,
        help_text='Recommended size: 500x500px'
    )

    def __str__(self):
        return self.name
    
    def save(self, *args, **kwargs):
        # Only process if image is being updated/added
        if self.image and not self.pk:
            self.image = self.compress_image(self.image)
        super().save(*args, **kwargs)

    def compress_image(self, image):
        """Compress image while maintaining quality"""
        img = Image.open(image)
        if img.mode != 'RGB':
            img = img.convert('RGB')
            
        # Resize logic
        max_size = (500, 500)
        if img.height > max_size[1] or img.width > max_size[0]:
            img.thumbnail(max_size, Image.LANCZOS)
        
        # Save to memory
        output = BytesIO()
        img.save(
            output,
            format='JPEG',
            quality=85,  # Good balance between quality and size
            optimize=True
        )
        output.seek(0)
        
        return InMemoryUploadedFile(
            output,
            'ImageField',
            f"{image.name.split('.')[0]}.jpg",
            'image/jpeg',
            sys.getsizeof(output),
            None
        )

class Project(models.Model):
    title = models.CharField(max_length=200)
    description = models.TextField(blank=True, null=True)
    target_amount = models.DecimalField(max_digits=10, decimal_places=2, validators=[MinValueValidator(0.01)])
    current_amount = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    is_active = models.BooleanField(default=True)
    project_type = models.ForeignKey(ProjectType, on_delete=models.SET_NULL, null=True, blank=True, related_name='projects')
    featured_image = models.ImageField(
        upload_to='projects/',
        validators=[validate_image_file_extension, validate_image_file_size],
        null=True,
        blank=True,
        help_text='Recommended size: 1200x800px'
    )

    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        # Only process if image is being updated/added
        if self.featured_image and (not self.pk or 'featured_image' in kwargs.get('update_fields', [])):
            self.featured_image = self.compress_image(self.featured_image)
        super().save(*args, **kwargs)

    def compress_image(self, image):
        """Compress image while maintaining quality"""
        img = Image.open(image)
        if img.mode != 'RGB':
            img = img.convert('RGB')
            
        # Resize logic - different dimensions for projects
        max_size = (1200, 800)
        if img.height > max_size[1] or img.width > max_size[0]:
            img.thumbnail(max_size, Image.LANCZOS)
        
        # Save to memory
        output = BytesIO()
        img.save(
            output,
            format='JPEG',
            quality=85,
            optimize=True
        )
        output.seek(0)
        
        return InMemoryUploadedFile(
            output,
            'ImageField',
            f"{image.name.split('.')[0]}.jpg",
            'image/jpeg',
            sys.getsizeof(output),
            None
        )
    
    @property
    def remaining_amount(self):
        return self.target_amount - self.current_amount
    
    @property
    def get_percentage_funded(self):
        if self.target_amount == 0:
            return 0
        return (self.current_amount / self.target_amount) * 100
    
    def get_donations_count(self):
        return self.donation_set.count()
    
    def get_recent_donations(self, limit=5):
        return self.donation_set.order_by('-donation_date')[:limit]
    
    def get_total_donors(self):
        return self.donation_set.values('user').distinct().count()

class Donation(models.Model):
    user = models.ForeignKey(UserAccount, on_delete=models.CASCADE, null=True, blank=True)
    project = models.ForeignKey(Project, on_delete=models.CASCADE)
    amount = models.DecimalField(max_digits=10, decimal_places=2, validators=[MinValueValidator(0.01)])
    donation_date = models.DateTimeField(auto_now_add=True)
    donator_name = models.CharField(max_length=255, null=True, blank=True)
    donator_mail = models.CharField(max_length=255, null=True, blank=True)
    donator_tel = models.CharField(max_length=255, null=True, blank=True)
    payment_method = models.CharField(max_length=50, choices=[
        ('paypal', 'PayPal'),
        ('stripe', 'Stripe'),
        ('flutterwave', 'Flutterwave'),
        ('cinetpay', 'CinetPay'),
    ])
    transaction_reference = models.CharField(max_length=100, blank=True, null=True)
    payment_metadata = models.JSONField(blank=True, null=True)  # Add this line
    payment_status = models.CharField(
        max_length=20,
        choices=[
            ('pending', 'Pending'),
            ('completed', 'Completed'),
            ('failed', 'Failed'),
            ('refunded', 'Refunded'),
        ],
        default='pending'
    )
    
    def mark_as_completed(self):
        self.payment_status = 'completed'
        self.save()
        self.project.current_amount = Donation.objects.filter(
            project=self.project, 
            payment_status='completed'
        ).aggregate(total=Sum('amount'))['total'] or 0
        self.project.save()

    def __str__(self):
        return f"{self.donator_name} donated {self.amount} to {self.project.title}"

    def save(self, *args, **kwargs):
        # Prevent donation if the project is inactive
        if not self.project.is_active:
            raise ValidationError("This project is no longer accepting donations.")

        # Prevent donation if the amount exceeds the remaining amount needed
        remaining_amount = self.project.remaining_amount
        if self.amount > remaining_amount:
            raise ValidationError(f"The donation amount exceeds the remaining amount needed for this project. Maximum allowed: ${remaining_amount}.")

        # Save the donation without updating the project's current amount
        super().save(*args, **kwargs)

class UserProfile(models.Model):
    user = models.OneToOneField(UserAccount, on_delete=models.CASCADE)
    total_donated = models.DecimalField(
        max_digits=10, 
        decimal_places=2, 
        default=0.00,
        null=True,
        blank=True
    )

    def __str__(self):
        return self.user.username


#Payments models ends
class Newsletter(models.Model):
    name = models.CharField(max_length=100)
    email = models.CharField(max_length=100, unique=True)
    registration_date = models.DateTimeField(auto_now_add=True)
    deactivated_date = models.DateTimeField(null=True, blank=True)
    u_active = models.BooleanField(default=True)

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

class todolist(models.Model):
    taskname = models.CharField(max_length=500, unique=True)
    inchargeperson = models.ForeignKey(UserLogin, on_delete=models.SET_NULL, null=True, blank=True, related_name='inchargetodo')
    duedate = models.DateField(null=True, blank=True)
    priority = models.CharField(max_length=50)
    status = models.CharField(max_length=50)
    is_active = models.BooleanField(default=True)
    adminid = models.ForeignKey(UserLogin, on_delete=models.SET_NULL, null=True, blank=True, related_name='admintodo')
    registered_on = models.DateTimeField(auto_now_add=True)



    def __str__(self):
        return f"{self.taskname} {self.status}"