import string

import uuid
from PIL import Image, ExifTags
from django.contrib.admin import display
from django.contrib.auth.models import User
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils.crypto import get_random_string
from imagekit.models import ProcessedImageField, ImageSpecField
from pilkit.processors import ResizeToFill, ResizeToCover

from apps.carers.lib.qr_code_gen import generate_qr_code
from apps.quiz.models import Quiz


# Create your models here.


class TimeStampMixin(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True


class Profile(TimeStampMixin):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    middle_names = models.CharField(max_length=100, null=True, blank=True)
    employer_name = models.CharField(max_length=100, null=True, blank=True)
    employer_email = models.EmailField(null=True, blank=True)
    has_completed_setup = models.BooleanField(default=False)
    hobbies = models.TextField(blank=True, null=True)
    extra_text = models.TextField(blank=True, null=True)
    avatar_thumbnail = ImageSpecField(source='avatar',
                                      processors=[ResizeToFill(110, 110)],
                                      format='WEBP',
                                      options={'quality': 90}
                                      )

    avatar = models.ImageField(upload_to='avatars', null=True, blank=True)

    pin = models.CharField(max_length=6, unique=True, blank=True, editable=False)
    qr_code = models.ImageField(upload_to='qr_codes', blank=True, null=True)
    preferred_name = models.CharField(max_length=180, null=True, blank=True)
    enabled_privacy_mode = models.BooleanField(default=False)
    display_name = models.CharField(max_length=180, null=True, blank=True)
    sent_welcome_email = models.BooleanField(default=False)

    def save(self, *args, **kwargs):
        # Save the instance first, to ensure the file is saved
        if not self.pin:
            # Generate a random, unique PIN for each new profile
            self.pin = self.generate_unique_pin()

        # Generate QR code when pin is created or updated
        if not self.qr_code:
            self.qr_code = generate_qr_code(self.pin)

        # Correct the image orientation after the instance (and thus the file) is saved
        if self.avatar and hasattr(self.avatar, 'file') and hasattr(self.avatar.file, 'name'):
            self.correct_image_orientation(self.avatar.path)
            # Re-save the instance if the image was corrected
            super(Profile, self).save(update_fields=['avatar'])

        self.display_name = self.calculate_display_name()

        super(Profile, self).save(*args, **kwargs)

    @staticmethod
    def correct_image_orientation(image_path):
        try:
            with Image.open(image_path) as image:
                exif = image._getexif()
                if exif:
                    for orientation in ExifTags.TAGS.keys():
                        if ExifTags.TAGS[orientation] == 'Orientation':
                            orientation_value = exif.get(orientation)
                            break

                    print(f"Image orientation: {orientation_value}")

                    # Adjust rotation logic as needed
                    if orientation_value == 3:
                        image = image.rotate(180, expand=True)
                    elif orientation_value == 6:
                        image = image.rotate(270, expand=True)  # 90 degrees clockwise
                    elif orientation_value == 8:
                        image = image.rotate(90, expand=True)  # 90 degrees counter-clockwise

                    image.save(image_path)

        except Exception as e:
            print(f"Error processing image: {e}")

    @staticmethod
    def generate_unique_pin():
        length = 6
        # Define the characters that can be used in the PIN
        allowed_chars = string.ascii_lowercase + string.digits
        pin = get_random_string(length=length, allowed_chars=allowed_chars)
        while Profile.objects.filter(pin=pin).exists():
            # Generate a new PIN if there is a clash
            pin = get_random_string(length=length, allowed_chars=allowed_chars)
        return pin

    def __str__(self):
        return self.display_name

    def calculate_display_name(self):
        # update name
        if self.user.first_name:
            if self.preferred_name:
                if self.enabled_privacy_mode:
                    return f'{self.user.first_name} {self.user.last_name[0]}.'
                else:
                    return f'{self.user.first_name} ({self.preferred_name}) {self.user.last_name}'
            else:
                if self.enabled_privacy_mode:
                    return f'{self.user.first_name} {self.user.last_name[0]}.'
                else:
                    return f'{self.user.first_name} {self.user.last_name}'

        else:
            return self.user.username


class Qualification(TimeStampMixin):
    name = models.CharField(max_length=200)
    user = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return self.name


class WorkExperience(TimeStampMixin):
    name = models.CharField(max_length=200)
    user = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return self.name


class Review(TimeStampMixin):
    STAR_CHOICES = (
        (1, '1 Star'),
        (2, '2 Stars'),
        (3, '3 Stars'),
        (4, '4 Stars'),
        (5, '5 Stars'),
    )

    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='reviews')
    rating = models.IntegerField(choices=STAR_CHOICES, default=5)
    text = models.TextField()
    # TODO: reviewer_name was the first implementation, we need some code to convert this field to first/last name fields
    reviewer_name = models.CharField(max_length=255, null=True, blank=True)
    reviewer_first_name = models.CharField(max_length=255, null=True, blank=True)
    reviewer_last_name = models.CharField(max_length=255, null=True, blank=True)
    reviewer_phone = models.CharField(max_length=255)
    reviewer_email = models.EmailField()
    relationship_to_user = models.CharField(max_length=255)
    is_flagged_for_review = models.BooleanField(default=False)
    display_initials_only = models.BooleanField(default=False)
    review_display_name = models.CharField(max_length=255)

    def save(self, *args, **kwargs):
        # set review display name
        if self.reviewer_first_name:
            if self.reviewer_last_name:
                if self.display_initials_only:
                    self.review_display_name = f"{self.reviewer_first_name[0]}{self.reviewer_last_name[0]}"
                else:
                    self.review_display_name = f"{self.reviewer_first_name} {self.reviewer_last_name[0]}."
            else:
                if self.display_initials_only:
                    self.review_display_name = f"{self.reviewer_first_name[0]}"
                else:
                    self.review_display_name = f"{self.reviewer_first_name}"

        super(Review, self).save(*args, **kwargs)




@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)



class UserActivationCode(TimeStampMixin):
    uuid = models.UUIDField(default=uuid.uuid4, editable=False)
    user = models.ForeignKey(User, on_delete=models.CASCADE, unique=True)
