# -*- coding:utf-8 -*-
import os
from PIL import Image
from bitfield.models import BitField

from jsonfield import JSONField
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser, PermissionsMixin
from django.core.validators import RegexValidator
from django.utils.translation import gettext_lazy as _
from django.conf import settings
from django.shortcuts import resolve_url
from group_app.models import Group


class MyUserManager(BaseUserManager):
    def create_user(self, telephone, username, password=None):
        """
        Creates and saves a User with the given email, date of
        birth and password.
        """
        if not telephone:
            raise ValueError(_('Users must have an telephone number'))

        user = self.model(
            telephone=telephone,
            username=username,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, telephone, username, password):
        """
        Creates and saves a superuser with the given email, date of
        birth and password.
        """
        user = self.create_user(telephone,
                                password=password,
                                username=username
                                )
        user.is_admin = True
        user.is_superuser = True
        user.save(using=self._db)
        return user


class BaseAccount(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(
        _('profile username'),
        max_length=127,
        unique=True,
        validators=(RegexValidator(r'^\w{1,127}$'),)
    )
    fio = models.CharField(_('fio'), max_length=256)
    birth_day = models.DateField(_('birth day'), auto_now_add=True)
    is_active = models.BooleanField(_('Is active'), default=True)
    is_admin = models.BooleanField(default=False)
    telephone = models.CharField(
        max_length=16,
        verbose_name=_('Telephone'),
        blank=True,
        validators=(RegexValidator(
            getattr(settings, 'TELEPHONE_REGEXP', r'^(\+[7893]\d{10,11})?$')
        ),)
    )

    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ('telephone',)

    def get_full_name(self):
        return self.fio if self.fio else self.username

    def get_short_name(self):
        return self.username or self.telephone

    # Use UserManager to get the create_user method, etc.
    objects = MyUserManager()

    @property
    def is_staff(self):
        " Is the user a member of staff?"
        # Simplest possible answer: All admins are staff
        return self.is_admin

    def __str__(self):
        return self.get_full_name()

    class Meta:
        db_table = 'base_accounts'
        ordering = 'username',


class UserProfileLog(models.Model):
    account = models.ForeignKey('UserProfile', on_delete=models.CASCADE, verbose_name=_('Author'))
    meta_info = JSONField(verbose_name=_('Meta information'))
    ACTION_TYPES = (
        ('cusr', _('Create user')),
        ('dusr', _('Delete user')),
        ('cdev', _('Create device')),
        ('ddev', _('Delete device')),
        ('cnas', _('Create NAS')),
        ('dnas', _('Delete NAS')),
        ('csrv', _('Create service')),
        ('dsrv', _('Delete service'))
    )
    do_type = models.CharField(_('Action type'), max_length=4, choices=ACTION_TYPES)
    additional_text = models.CharField(_('Additional info'), blank=True, null=True, max_length=512)
    action_date = models.DateTimeField(_('Action date'), auto_now_add=True)

    def __str__(self):
        return self.get_do_type_display()

    class Meta:
        ordering = '-action_date',
        verbose_name = _('User profile log')
        verbose_name_plural = _('User profile logs')


class UserProfileManager(MyUserManager):
    def get_profiles_by_group(self, group_id):
        return self.filter(responsibility_groups__id__in=(group_id,), is_admin=True, is_active=True)


class UserProfile(BaseAccount):
    avatar = models.ImageField(_('Avatar'), upload_to=os.path.join('user', 'avatar'), null=True, default=None, blank=True)
    email = models.EmailField(default='', blank=True)
    responsibility_groups = models.ManyToManyField(Group, blank=True, verbose_name=_('Responsibility groups'))
    USER_PROFILE_FLAGS = (
        ('notify_task', _('Notification about tasks')),
        ('notify_msg', _('Notification about messages')),
        ('notify_mon', _('Notification from monitoring'))
    )
    flags = BitField(flags=USER_PROFILE_FLAGS, default=0, verbose_name=_('Settings flags'))

    objects = UserProfileManager()

    def get_big_ava(self):
        if self.avatar and os.path.isfile(self.avatar.path):
            return self.avatar.url
        else:
            return getattr(settings, 'DEFAULT_PICTURE', '/static/img/user_ava.gif')

    def get_min_ava(self):
        return self.get_big_ava()

    class Meta:
        verbose_name = _('Staff account profile')
        verbose_name_plural = _('Staff account profiles')
        ordering = 'fio',

    def _thumbnail_avatar(self):
        if self.avatar and os.path.isfile(self.avatar.path):
            im = Image.open(self.avatar)
            im.thumbnail((200, 121), Image.ANTIALIAS)
            im.save(self.avatar.path)

    def save(self, *args, **kwargs):
        r = super().save(*args, **kwargs)
        self._thumbnail_avatar()
        return r

    def log(self, request_meta: dict, do_type: str, additional_text=None) -> None:
        """
        Make log about administrator actions.
        :param request_meta: META from django request.
        :param do_type: Choice from UserProfileLog.ACTION_TYPES
        :param additional_text: Additional information for action
        :return: None
        """
        inf = {
            'src_ip': request_meta.get('REMOTE_ADDR'),
            'username': request_meta.get('USER'),
            'hostname': request_meta.get('HOSTNAME'),
            'useragent': request_meta.get('HTTP_USER_AGENT')
        }
        UserProfileLog.objects.create(
            account=self,
            meta_info=inf,
            do_type=do_type,
            additional_text=additional_text
        )

    def get_absolute_url(self):
        return resolve_url('acc_app:other_profile', self.pk)
