# -*- coding: utf-8 -*-
from .models import *
from datetime import datetime, timedelta, date
from django.db.models import Q, F, Value as V
from django.db.models.functions import ExtractYear, Concat, Coalesce
from functools import reduce
from operator import or_

sales_department_groups = [
    'Отдел продаж: Начальник отдела продаж',
    'Отдел продаж: Менеджер отдела продаж',
    'Отдел продаж: Региональный руководитель отдела продаж',
    'Отдел продаж: Стажер отдела продаж'
]

heads_of_sales_groups = [
    'Отдел продаж: Начальник отдела продаж',
    'Отдел продаж: Региональный руководитель отдела продаж',
]


def get_personal_companies_by_managers_list(managers_list, filter_kwargs={}, exclude_kwargs={}, only_emails=False):
    try:
        users = User.objects.filter(
            user_profile__company_obj__manager_obj__in=managers_list,
            **filter_kwargs
        ).exclude(
            **exclude_kwargs
        ).order_by('-is_active', 'last_name', 'first_name')

        if only_emails:
            users = list(users.values_list('email', flat=True))

    except Exception as e:
        msg = f'get_personal_companies_by_managers_list Error = {str(e)}'
        users = []

    return users


def get_head_staffs_by_user_email(user_email, only_emails=False):
    try:
        user = User.objects.get(email=user_email)
        heads = get_head_staffs(user.user_profile, only_emails=True)
    except User.DoesNotExist as e:
        heads = None
    return heads


def get_head_staffs(user_profile_or_user_ID, only_emails=False):
    if type(user_profile_or_user_ID) == str:
        user = User.objects.get(id=int(user_profile_or_user_ID))
        user_profile = user.user_profile
    else:
        user_profile = user_profile_or_user_ID
        user = user_profile.user

    groups = user.groups.all()
    groups_name_list = groups.values_list('name', flat=True)

    Q_list = []

    if user_profile.is_sales_department_staff():
        if 'Отдел продаж: Менеджер отдела продаж' in groups_name_list:
            groups_list = ['Отдел продаж: Региональный руководитель отдела продаж']
            kwargs = {
                'groups__name__in': groups_list,
                'user_profile__regions__in': user.user_profile.regions.all(),
            }
            Q_list.append(Q(**kwargs))

        if not 'Отдел продаж: Начальник отдела продаж' in groups_name_list:
            groups_list = ['Отдел продаж: Начальник отдела продаж']
            kwargs = {'groups__name__in': groups_list}
            Q_list.append(Q(**kwargs))

    # groups_list = ['Управляющий']
    # kwargs.update({'groups__name__in': groups_list})
    if not 'Управляющий' in groups_name_list:
        kwargs = {'is_superuser': True}
        Q_list.append(Q(**kwargs))

    Q_obj = reduce(lambda p1, p2: (p1 | p2), Q_list)
    heads = User.objects.filter(
        Q_obj,
        is_active=True,
        is_staff=True
    )

    heads = heads.distinct().order_by('-is_active', 'last_name', 'first_name')

    if only_emails:
        heads = list(heads.values_list('email', flat=True))

    return heads


def get_bosses_and_subordinate_staff_ids(user, only_active=False, include_cur_user=False, only_emails=False):
    users = []

    kwargs = {
        'is_staff': True,
    }

    if only_active:
        kwargs.update({'is_active': True})

    groups = user.groups.all()
    groups_name_list = groups.values_list('name', flat=True)

    Q_obj = Q()

    if 'Отдел продаж: Начальник отдела продаж' in groups_name_list:
        Q_obj.add(Q(is_superuser=True), Q.OR)

    elif 'Отдел продаж: Региональный руководитель отдела продаж' in groups_name_list:
        Q_obj.add(Q(is_superuser=True), Q.OR)
        Q_obj.add(Q(groups__name='Отдел продаж: Начальник отдела продаж'), Q.OR)

    elif 'Отдел продаж: Менеджер отдела продаж' in groups_name_list:
        Q_obj.add(Q(is_superuser=True), Q.OR)
        Q_obj.add(Q(groups__name='Отдел продаж: Начальник отдела продаж'), Q.OR)
        Q_obj.add(Q(
            groups__name='Отдел продаж: Региональный руководитель отдела продаж',
            user_profile__regions__in=user.user_profile.regions.all()), Q.OR)

    subordinate_users = get_subordinate_staff(
        user, only_active=only_active, include_cur_user=include_cur_user, only_emails=only_emails
    )
    res_val = 'id'
    if only_emails:
        res_val = 'user_profile__email'

    subordinate_users = subordinate_users.values_list(res_val, flat=True)

    if user.is_superuser:
        users = subordinate_users
    else:
        bosses = User.objects.filter(Q_obj, **kwargs).values_list(res_val, flat=True)
        users = set(subordinate_users) | set(bosses)

    return users


def get_subordinate_sales_staff(user, groups, only_active=False, only_emails=False, include_cur_user=False):
    kwargs = {
        'is_staff': True,
    }

    if only_active:
        kwargs.update({'is_active': True})

    Q_obj = Q()

    if 'Отдел продаж: Начальник отдела продаж' in groups:
        kwargs_groups = [
            'Отдел продаж: Менеджер отдела продаж',
            'Отдел продаж: Региональный руководитель отдела продаж',
            'Отдел продаж: Стажер отдела продаж'
        ]
        Q_obj.add(Q(groups__name__in=kwargs_groups), Q.OR)


    elif u'Отдел продаж: Региональный руководитель отдела продаж' in groups:
        kwargs_groups = [
            'Отдел продаж: Менеджер отдела продаж',
            'Отдел продаж: Стажер отдела продаж'
        ]
        Q_obj.add(Q(groups__name__in=kwargs_groups, user_profile__regions__in=user.user_profile.regions.all()), Q.OR)

    elif u'Отдел продаж: Менеджер отдела продаж' in groups:
        kwargs_groups = [
            'Отдел продаж: Стажер отдела продаж'
        ]
        Q_obj.add(Q(groups__name__in=kwargs_groups, user_profile__regions__in=user.user_profile.regions.all()), Q.OR)

    elif 'Отдел закупок: Начальник отдела закупок' in groups:
        kwargs_groups = [
            'Отдел закупок: Менеджер отдела закупок',
        ]
        Q_obj.add(Q(groups__name__in=kwargs_groups), Q.OR)

    if include_cur_user:
        Q_obj.add(Q(id=user.id), Q.OR)

    users = User.objects.filter(Q_obj, **kwargs).exclude(is_superuser=True)
    users = users.distinct().order_by('-is_active', 'last_name', 'first_name')

    # if kwargs:
    #     other_users = User.objects.filter(
    #         **kwargs
    #     ).exclude(
    #         is_superuser=True
    #     )
    #     users = users.union(other_users)
    #     users = users.distinct().order_by('-is_active', 'last_name', 'first_name')

    if only_emails:
        users = list(users.values_list('email', flat=True))

    return users


def get_subordinate_staff(user, only_active=False, include_cur_user=False, only_emails=False):
    users = []

    groups = user.groups.all()
    groups_name_list = groups.values_list('name', flat=True)

    # отдел продаж
    if set(groups_name_list):
        users = get_subordinate_sales_staff(user, groups_name_list, include_cur_user=include_cur_user)

    if not users and user.is_superuser:
        users = get_all_staff()

    if not users and include_cur_user:
        users = User.objects.filter(id=user.id)

    if users and only_active:
        users = users.filter(is_active=True)

    if only_emails:
        users = list(users.values_list('email', flat=True))

    return users


def get_all_staff(only_active=False, only_emails=False):
    kwargs = {
        'is_staff': True,
    }
    if only_active:
        kwargs.update({'is_active': True})

    users = User.objects.filter(**kwargs).order_by('-is_active', 'last_name', 'first_name')

    if only_emails:
        users = list(users.values_list('email', flat=True))
    return users


def get_managers_wo_work():
    managers = get_sales_managers()
    managers = managers.filter(
        user_profile__last_web_request__lt=datetime.now() - timedelta(minutes=20),
        user_profile__last_web_request__contains=date.today()
    )

    return managers


def get_birthdays(manager=None, for_next_count_days=None, only_first=False):
    from_D = datetime.now()
    Q_obj = Q()
    Q_obj.add(Q(Q(birthdate__day=from_D.day) & Q(birthdate__month=from_D.month)), Q.OR)

    # в for_next_count_days количество будущих дней для которых собираем дни рождения
    if for_next_count_days:
        for i in range(1, for_next_count_days):
            Q_obj.add(Q(Q(birthdate__day=(from_D + timedelta(days=i)).day) & Q(
                birthdate__month=(from_D + timedelta(days=i)).month)), Q.OR)

    kwargs = {}
    if manager:
        kwargs.update({
            'company_obj__manager_obj': manager,

        })

    from .models import UserProfile
    user_profiles = UserProfile.objects.filter(
        Q_obj,
        # birthdate__lte=(datetime.now() + timedelta(days=3)).date(),
        # birthdate__gte=datetime.now().date()
        **kwargs
    ).annotate(
        age=datetime.now().year - ExtractYear('birthdate')
    ).order_by('company_obj__manager_obj', 'birthdate')

    if user_profiles and only_first:
        return user_profiles[0]

    return user_profiles


def get_sales_managers(only_active=False, only_emails=False):
    from CompaniesApp.models import Company

    kwargs = {
        'is_staff': True,
        'companies_for_manager__company_type': 'client',
    }
    if only_active:
        kwargs.update({'is_active': True})

    managers = User.objects.filter(**kwargs).exclude(companies_for_manager=None).distinct().order_by('-is_active',
                                                                                                     'last_name',
                                                                                                     'first_name')

    # managers = Company.objects.filter(
    #     company_type='client'
    # ).values_list('manager_obj', flat=True).distinct()

    if only_emails:
        managers = list(managers.values_list('email', flat=True))
    return managers


def get_full_names_by_id(ids):
    names = User.objects.filter(
        id__in=ids
    ).annotate(
        fullname=Concat(F('last_name'), V(' '), F('first_name'))
    ).values('id', 'fullname')
    names = {item['id']: item['fullname'] for item in names}

    return names


def fullname_for_user(user):
    full_name = '%s %s' % (user.last_name, user.first_name)
    return full_name.strip()


def get_heads_of_sales(only_active=False, only_emails=False):
    kwargs = {
        'is_staff': True,
    }

    Q_obj = Q(groups__name__in=heads_of_sales_groups) | Q(is_superuser=True)

    if only_active:
        kwargs.update({'is_active': True})

    users = User.objects.filter(
        Q_obj,
        **kwargs
    ).order_by('-is_active', 'last_name', 'first_name')

    if only_emails:
        users = list(users.values_list('email', flat=True))
    return users


def get_sales_department_staff(regions=None, only_active=False, only_emails=False):
    kwargs = {
        'is_staff': True,
    }

    if not regions:
        sales_department_groups = [
            'Отдел продаж: Менеджер отдела продаж', 'Отдел продаж: Начальник отдела продаж',
            'Отдел продаж: Региональный руководитель отдела продаж',
            'Отдел продаж: Стажер отдела продаж'
        ]
        kwargs.update({
            'groups__name__in': sales_department_groups,
        })

    else:
        sales_department_groups = [
            'Отдел продаж: Менеджер отдела продаж',
            'Отдел продаж: Региональный руководитель отдела продаж',
            'Отдел продаж: Стажер отдела продаж'
        ]
        kwargs.update({
            'groups__name__in': sales_department_groups,
        })

    if only_active:
        kwargs.update({'is_active': True})

    users = User.objects.filter(**kwargs).exclude(is_superuser=True).order_by('-is_active', 'last_name', 'first_name')
    if only_emails:
        users = list(users.values_list('email', flat=True))
    return users


def get_marketing_departament_persons(only_active=False, only_emails=False):
    kwargs = {
        'is_staff': True,
        'groups__name': 'Маркетинг: Маркетолог',
    }
    if only_active:
        kwargs.update({'is_active': True})

    users = User.objects.filter(**kwargs).order_by('-is_active', 'last_name', 'first_name')

    if only_emails:
        users = list(users.values_list('email', flat=True))
    return users
