import os

from django.conf import settings
from django.db import models
from django.utils.html import format_html
from django.utils import timezone

from . import ProfileType


def entry_thumbnail_path(instance, filename):
    return 'images/user-avatars/{timestamp}{ext}'.format(
        timestamp=str(timezone.now()),
        ext=os.path.splitext(filename)[1]
    )


class UserProfileQuerySet(models.query.QuerySet):
    """
    A queryset for profiles with convenience queries
    """

    def limit(self, size):
        """
        Limit the results to a fixed size subset
        """
        return self[:size]

    def active(self):
        """
        Return all profiles that have the is_active flag set to True
        """
        return self.filter(is_active=True)


class UserProfile(models.Model):
    """
    This class houses all user profile information,
    such as real name, social media information,
    bookmarks on the site, etc.
    """

    # make sure we record when a profile got created.
    created_at = models.DateTimeField(
        auto_now_add=True
    )

    # This flag determines whether this profile has been
    # activated, meaning it can be retrieved through REST
    # API calls and might get crosslinked into data structures
    # that rely on knowing a user or group's profile.
    is_active = models.BooleanField(
        default=False
    )

    # "user X bookmarked entry Y" is a many to many relation,
    # for which we also want to know *when* a user bookmarked
    # a specific entry. As such, we use a helper class that
    # tracks this relation as well as the time it's created.
    bookmarks = models.ManyToManyField(
        'entries.Entry',
        through='profiles.UserBookmarks'
    )

    # The name field is an alternative name to be used if the
    # associated user(s) don't want to expose their login-indicated
    # name instead.
    #
    # Examples of this are nicknames, pseudonyms, and org names
    custom_name = models.CharField(
        max_length=140,
        blank=True
    )

    custom_name.short_description = 'Custom user name'

    # Accessing the Profile-indicated name needs various stages
    # of fallback.
    # Note that we cannot use this accessor as a lookup field in querysets
    # because it is not an actual field.
    @property
    def name(self):
        custom_name = self.custom_name

        # blank values, including pure whitespace, don't count:
        if not custom_name or not custom_name.strip():
            user = self.user
            return user.name if user else None

        # anything else does count.
        return custom_name

    # We provide an easy accessor to the profile's user because
    # accessing the reverse relation (using related_name) can throw
    # a RelatedObjectDoesNotExist exception for orphan profiles.
    # This allows us to return None instead.
    #
    # Note: we cannot use this accessor as a lookup field in querysets
    #       because it is not an actual field.
    @property
    def user(self):
        # Import EmailUser here to avoid circular import
        from pulseapi.users.models import EmailUser
        try:
            return self.related_user
        except EmailUser.DoesNotExist:
            return None

    # This flag marks whether or not this profile applies to
    # "A human being", or a group of people (be that a club, org,
    # institution, etc. etc.)
    is_group = models.BooleanField(
        default=False
    )

    is_group.short_description = 'This is a group profile.'

    # We deal with location by asking users to just write their
    # location as they would if they were search maps for it.
    location = models.CharField(
        max_length=1024,
        blank=True
    )

    location.short_description = 'User location (as would be typed in a maps search)'

    # Thumbnail image for this user; their "avatar" even though we
    # do not have anything on the site right now where avatars
    # come into play.
    thumbnail = models.ImageField(
        max_length=2048,
        upload_to=entry_thumbnail_path,
        blank=True
    )

    def thumbnail_image_tag(self):
        if not self.thumbnail:
            return format_html('<span>No image to preview</span>')

        media_url = settings.MEDIA_URL

        if settings.USE_S3:
            media_url = 'https://{domain}/{bucket}/'.format(
                domain=settings.AWS_S3_CUSTOM_DOMAIN,
                bucket=settings.AWS_LOCATION
            )

        html = '<img src="{media_url}{src}" style="width:25%">'.format(
            media_url=media_url,
            src=self.thumbnail
        )

        return format_html(html)

    thumbnail_image_tag.short_description = 'Thumbnail preview'

    # Which issues does this user care about/are they involved in?
    issues = models.ManyToManyField(
        'issues.Issue',
        blank=True,
    )

    # we allow users to indicate several possible predefined service URLs
    twitter = models.URLField(
        max_length=2048,
        blank=True
    )

    linkedin = models.URLField(
        max_length=2048,
        blank=True
    )

    github = models.URLField(
        max_length=2048,
        blank=True
    )

    website = models.URLField(
        max_length=2048,
        blank=True
    )

    # --- extended information ---

    enable_extended_information = models.BooleanField(
        default=False
    )

    # TODO: Deprecate
    profile_type = models.ForeignKey(
        'profiles.ProfileType',
        null=True,
        blank=True,
        on_delete=models.SET_NULL
        # default is handled in save()
    )

    # TODO: Deprecate
    program_type = models.ForeignKey(
        'profiles.ProgramType',
        null=True,
        blank=True,
        on_delete=models.SET_NULL
    )

    # TODO: Deprecate
    program_year = models.ForeignKey(
        'profiles.ProgramYear',
        null=True,
        blank=True,
        on_delete=models.SET_NULL
    )

    # Free form affiliation information
    affiliation = models.CharField(
        max_length=200,
        blank=True
    )

    # A tweet-style user bio
    user_bio = models.CharField(
        max_length=212,
        blank=True
    )

    # A long-form user bio
    user_bio_long = models.TextField(
        max_length=4096,
        blank=True
    )

    objects = UserProfileQuerySet.as_manager()

    def save(self, *args, **kwargs):
        if self.profile_type is None:
            self.profile_type = ProfileType.get_default_profile_type()
        super(UserProfile, self).save(*args, **kwargs)

    def __str__(self):
        if self.user is None:
            return f'{self.custom_name} (no user)'

        return f'{self.name} ({self.user.email})'

    class Meta:
        verbose_name = "Profile"
