import uuid
from django.db import models
from django.contrib.auth.models import (
    BaseUserManager, 
    AbstractBaseUser,
    PermissionsMixin
)
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError

from base64 import b32encode
from hashlib import sha1
from random import random

class UserAccountManager(BaseUserManager):
    def create_user(self, email, password=None, **kwargs):
        if not email:
            raise ValueError('Users must have an email address')

        email = self.normalize_email(email)
        email = email.lower()

        user = self.model(
            email=email,
            **kwargs
        )
        user.is_active = False
        user.set_password(password)
        user.save(using=self._db)
        if user.role=="2":
            agent,create = Agent.objects.get_or_create(user__email=email)
            agent.user = user
            agent.save()
        elif user.role=="3":
            organization,create = Organization.objects.get_or_create(user__email=email)
            organization.user = user
            organization.save()
        profile,create = UserProfile.objects.get_or_create(user=user)
        profile.save()
        return user

    def create_superuser(self, email, password=None, **kwargs):
        user = self.create_user(
            email,
            password=password,
            **kwargs
        )

        user.is_active = True
        user.is_staff = True
        user.is_superuser = True
        user.save(using=self._db)

        return user

role_choice=(
    ('1','General User'),
    ('2','Agent'),
    ('3','Organization')
) 

class UserAccount(AbstractBaseUser, PermissionsMixin):
    full_name = models.CharField(max_length=60, null=True)
    email = models.EmailField(unique=True, max_length=255)
    phone = models.CharField(max_length=16, null=True)
    role = models.CharField(
        max_length=15,
        choices=role_choice,
        default='1'
    )

    profile_picture = models.ImageField(upload_to='profile_pictures/', null=True, blank=True, default='default_avatar.jpg')

    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)

    objects = UserAccountManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ["full_name", "phone", "role"]

    def __str__(self):
        return self.email + " ->" + str(self.id)
    
class UserProfile(models.Model):
    user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE)
    skype_link = models.URLField(blank=True,default="",null=True)
    facebook_link = models.URLField(blank=True,default="",null=True)
    linkedin_link = models.URLField(blank=True,default="",null=True)
    title = models.CharField(max_length=255, blank=True,default="",null=True)
    website = models.URLField(blank=True,default="",null=True)
    twitter = models.URLField(blank=True,default="",null=True)
    pinterest = models.URLField(blank=True,default="",null=True)
    description = models.TextField(blank=True,default="",null=True)

    def __str__(self):
        return str(self.user)

class Organization(models.Model):
    agents = models.ManyToManyField('Agent', blank=True,related_name='organizations_associated')
    user = models.ForeignKey(get_user_model(), on_delete=models.SET_NULL, null=True)

    def __str__(self):
        return str(self.user)
    
class Agent(models.Model):
    user = models.ForeignKey(get_user_model(), on_delete=models.SET_NULL, null=True)

    def __str__(self):
        return "User:"+str(self.user)+"---"+"Agent ID: "+str(self.id)

class Invitation(models.Model):
    organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
    agent = models.ForeignKey(Agent, on_delete=models.CASCADE)
    is_accepted = models.BooleanField(default=False)
    is_rejected = models.BooleanField(default=False)

    def __str__(self):
        return f'Invitation to {self.organization} for {self.agent.user.email} : {str(self.id)}'

class Message(models.Model):
    sender = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='sender')
    recipient = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='recipient')
    message = models.TextField()
    date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.message

    class Meta:
        ordering = ('-date',)

    # function gets all messages between 'the' two users (requires your pk and the other user pk)
    def get_all_messages(id_1, id_2):
        messages = []
        # get messages between the two users, sort them by date(reverse) and add them to the list
        message1 = Message.objects.filter(sender_id=id_1, recipient_id=id_2).order_by('-date') # get messages from sender to recipient
        for x in range(len(message1)):
            messages.append(message1[x])
        message2 = Message.objects.filter(sender_id=id_2, recipient_id=id_1).order_by('-date') # get messages from recipient to sender
        for x in range(len(message2)):
            messages.append(message2[x])

        # because the function is called when viewing the chat, we'll return all messages as read
        for x in range(len(messages)):
            messages[x].is_read = True
        # sort the messages by date
        messages.sort(key=lambda x: x.date, reverse=False)
        return messages 
      
     # function gets all messages between 'any' two users (requires your pk)
    def get_message_list(u):
        # get all the messages
        m = []  # stores all messages sorted by latest first
        j = []  # stores all usernames from the messages above after removing duplicates
        k = []  # stores the latest message from the sorted usernames above
        for message in Message.objects.all():
            for_you = message.recipient == u  # messages received by the user
            from_you = message.sender == u  # messages sent by the user
            if for_you or from_you:
                m.append(message)
                m.sort(key=lambda x: x.sender.email)  # sort the messages by senders
                m.sort(key=lambda x: x.date, reverse=True)  # sort the messages by date

        # remove duplicates usernames and get single message(latest message) per username(other user) (between you and other user)
        for i in m:
            if i.sender.email not in j or i.recipient.email not in j:
                j.append(i.sender.email)
                j.append(i.recipient.email)
                k.append(i)

        return k
    
    @staticmethod
    def get_users_with_messages(current_user):
        users_with_messages = set()

        # Get all messages involving the current user
        for message in Message.objects.filter(sender=current_user) | Message.objects.filter(recipient=current_user):
            if message.sender != current_user:
                users_with_messages.add(message.sender)
            if message.recipient != current_user:
                users_with_messages.add(message.recipient)

        # Convert the set of users to a list
        users_list = list(users_with_messages)

        return users_list
# class Conversation(models.Model):
#     participants = models.ManyToManyField(get_user_model(), related_name='conversations')
#     created_at = models.DateTimeField(auto_now_add=True)
#     def clean(self):
#         if self.participants.count() != 2:
#             raise ValidationError("A conversation must have exactly two participants.")
#         super().clean()
        
# class Message(models.Model):
#     conversation = models.ForeignKey(Conversation, on_delete=models.CASCADE, related_name='messages')
#     sender = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='sent_messages')
#     text = models.TextField()
#     timestamp = models.DateTimeField(auto_now_add=True)

from django.db import models
from django.contrib.auth import get_user_model
from django.utils import timezone

###############################################################################
# 1. Wallet – one-per-user, holds the current balance
###############################################################################
class Wallet(models.Model):
    user    = models.OneToOneField(
                get_user_model(),
                on_delete=models.CASCADE,
                related_name='wallet'
              )
    balance = models.DecimalField(max_digits=12, decimal_places=2, default=0)

    def __str__(self):
        return f"{self.user.email} → {self.balance}"


###############################################################################
# 2. SubscriptionPackage – the "plan" catalog
###############################################################################
class SubscriptionPackage(models.Model):
    name = models.CharField(max_length=100, unique=True)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    # --- New fields below ---
    hide_address_count = models.PositiveIntegerField(default=0)
    hide_contact_count = models.PositiveIntegerField(default=0)
    boost_count = models.PositiveIntegerField(default=0)
    analytics_support = models.BooleanField(default=False)

    def __str__(self):
        return f"{self.name} ({self.price})"

from datetime import timedelta
###############################################################################
# 3. Subscription – a user's active or historical subscription
###############################################################################
class Subscription(models.Model):
    user = models.ForeignKey(
        get_user_model(),
        on_delete=models.CASCADE,
        related_name='subscriptions'
    )
    package = models.ForeignKey(
        SubscriptionPackage,
        on_delete=models.CASCADE,
        related_name='subscriptions'
    )
    subscription_date = models.DateTimeField(default=timezone.now)
    duration_days = models.PositiveIntegerField(default=30)
    expiry_date = models.DateTimeField(blank=True, null=True)

    # --- Copied utilities ---
    hide_address_count = models.PositiveIntegerField(default=0)
    hide_contact_count = models.PositiveIntegerField(default=0)
    boost_count = models.PositiveIntegerField(default=0)
    analytics_support = models.BooleanField(default=False)

    def save(self, *args, **kwargs):
        if self.pk is None:
            self.hide_address_count = self.package.hide_address_count
            self.hide_contact_count = self.package.hide_contact_count
            self.boost_count = self.package.boost_count
            self.analytics_support = self.package.analytics_support

        if not self.expiry_date:
            self.expiry_date = self.subscription_date + timedelta(days=self.duration_days)
        super().save(*args, **kwargs)


    def is_active(self):
        return timezone.now() < self.expiry_date

    def __str__(self):
        return f"{self.user.email} → {self.package.name} @ {self.subscription_date:%Y-%m-%d}"


from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=get_user_model())
def create_user_wallet(sender, instance, created, **kwargs):
    if created:
        Wallet.objects.get_or_create(user=instance)

class WalletTransaction(models.Model):
    TRANSACTION_TYPE_CHOICES = [
        ('credit', 'Credit'),   # adding funds
        ('debit', 'Debit'),     # spending funds
    ]

    user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='transactions')
    amount = models.DecimalField(max_digits=12, decimal_places=2)
    transaction_type = models.CharField(max_length=10, choices=TRANSACTION_TYPE_CHOICES)
    purpose = models.CharField(max_length=255, help_text="Reason for the transaction")
    timestamp = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.user.email} - {self.transaction_type} - {self.amount} on {self.timestamp:%Y-%m-%d %H:%M}"

class StripeRecharge(models.Model):
    user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
    session_id = models.CharField(max_length=255, unique=True)
    amount = models.DecimalField(max_digits=12, decimal_places=2)
    success = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.user.email} | {self.amount} | {'✅' if self.success else '❌'}"

class PayPalRecharge(models.Model):
    user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
    payment_id = models.CharField(max_length=255, unique=True)
    payer_id = models.CharField(max_length=255, blank=True, null=True)
    amount = models.DecimalField(max_digits=12, decimal_places=2)
    success = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.user.email} | {self.amount} | {'✅' if self.success else '❌'}"


from django.db import models
from django.conf import settings
from django.utils import timezone

class Coupon(models.Model):
    code = models.CharField(max_length=32, unique=True)
    description = models.CharField(max_length=255, blank=True)
    is_active = models.BooleanField(default=True)
    discount_type = models.CharField(max_length=8, choices=(('flat', 'Flat'), ('percent', 'Percent')))
    discount_value = models.DecimalField(max_digits=10, decimal_places=2)
    max_uses = models.PositiveIntegerField(default=1)
    expires_at = models.DateTimeField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    def is_valid(self):
        now = timezone.now()
        return self.is_active and (self.expires_at is None or self.expires_at > now)

class CouponUsage(models.Model):
    coupon = models.ForeignKey(Coupon, on_delete=models.CASCADE)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    used_at = models.DateTimeField(auto_now_add=True)


# users/models.py

class IdentityDocumentType(models.Model):
    name = models.CharField(max_length=64, unique=True)
    description = models.TextField(blank=True)
    requires_photo = models.BooleanField(default=True)  # Always true, but keeps it explicit

    def __str__(self):
        return self.name

class VerificationDiscount(models.Model):
    package = models.OneToOneField('SubscriptionPackage', on_delete=models.CASCADE, related_name='verification_discount')
    discount_type = models.CharField(max_length=8, choices=(('flat', 'Flat'), ('percent', 'Percent')))
    discount_value = models.DecimalField(max_digits=8, decimal_places=2)

    def __str__(self):
        return f"{self.package.name}: {self.discount_type} {self.discount_value}"


from django.conf import settings
from django.utils import timezone
from datetime import timedelta

class UserVerification(models.Model):
    STATUS_CHOICES = (
        ('pending', 'Pending'),
        ('approved', 'Approved'),
        ('rejected', 'Rejected'),
        ('expired', 'Expired'),
    )
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='verifications')
    document_type = models.ForeignKey(IdentityDocumentType, on_delete=models.PROTECT)
    document_image = models.ImageField(upload_to='identity_documents/')
    document_number = models.CharField(max_length=64, blank=True)
    selfie_image = models.ImageField(upload_to='identity_selfies/', blank=True)  # optional: selfie holding doc
    status = models.CharField(max_length=12, choices=STATUS_CHOICES, default='pending')
    applied_at = models.DateTimeField(auto_now_add=True)
    verified_at = models.DateTimeField(null=True, blank=True)
    rejected_reason = models.TextField(blank=True)
    expiry_date = models.DateTimeField(null=True, blank=True)
    verification_fee = models.DecimalField(max_digits=8, decimal_places=2)
    paid = models.BooleanField(default=False)

    def is_active(self):
        return self.status == 'approved' and (self.expiry_date is None or self.expiry_date > timezone.now())

    def renew(self, months=1, fee=None):
        self.status = 'pending'
        self.applied_at = timezone.now()
        self.verified_at = None
        self.rejected_reason = ""
        self.expiry_date = timezone.now() + timedelta(days=30 * months)
        if fee is not None:
            self.verification_fee = fee
        self.paid = False
        self.save()

    def __str__(self):
        return f"{self.user} - {self.document_type} ({self.status})"

class UserVerificationManager(models.Manager):
    def active(self, user):
        return self.filter(user=user, status='approved', expiry_date__gt=timezone.now()).first()


class VerificationFee(models.Model):
    price = models.DecimalField(max_digits=8, decimal_places=2)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"Verification Fee: {self.price}"
