from BaseModels.mailSender import techSendMail
from django.db.models import Sum, FloatField, F, Value as V, Count, OuterRef, Subquery, Q, Max, Exists
from django.db.models.functions import Concat, Length
from operator import itemgetter
from datetime import datetime
import copy
from .models import User
from datetime import datetime, date, timedelta
from collections import OrderedDict


def managers_sales_by_period_n_regions(period_from=None, period_to=None, region_ids=None, kwargs=None, sum_w_prev_data=None):
    from CompaniesApp.models import Company

    log_begin_DT = datetime.now()
    msg = 'managers_sales_by_period_n_regions start - {0}<br>---------------<br><br>'.format(str(log_begin_DT))
    print(msg)


    stat_kwargs = {}
    queryset_kwargs = {}
    all_managers = False
    separate_managers_sales_by_link_in_order = False
    if kwargs:
        if 'stat_kwargs' in kwargs:
            stat_kwargs.update(kwargs['stat_kwargs'])


        if 'all_managers' in kwargs:
            all_managers = kwargs['all_managers']


        if 'queryset_kwargs' in kwargs:
            queryset_kwargs.update(kwargs['queryset_kwargs'])


        if 'separate_managers_sales_by_link_in_order' in kwargs:
            separate_managers_sales_by_link_in_order = kwargs['separate_managers_sales_by_link_in_order']


    from B2BApp.stat_funcs import get_sales_by_period_n_regions
    orders, receipts, pays = get_sales_by_period_n_regions(period_from=period_from, period_to=period_to, region_ids=region_ids, kwargs=kwargs)


    ids = []
    if not all_managers:

        ord_manager_ids = set(item['manager_obj__id'] for item in orders)
        receipt_manager_ids = set(item['manager_obj__id'] for item in receipts)
        pay_manager_ids = set(item['manager__id'] for item in pays)

        ids = set.union(ord_manager_ids, receipt_manager_ids, pay_manager_ids)

        queryset_kwargs.update({'id__in': ids})

    if not sum_w_prev_data:
        managers = User.objects.filter(
            **queryset_kwargs
        ).annotate(
            full_name=Concat(F('last_name'), V(' '), F('first_name')),
        ).order_by('full_name').values(
            'id', 'full_name'
        )

        objs = list(managers)
        objs.sort(key=itemgetter('full_name'), reverse=False)
        if None in ids:
            objs.append({'id': None, 'full_name': 'не назначен менеджер'})
    else:
        objs = copy.deepcopy(sum_w_prev_data)

    from_date = None
    to_date = None
    if orders:
        orders.sort(key=itemgetter('delivery_DT'), reverse=False)
        from_date = orders[0]['delivery_DT'].date()
        to_date = orders[-1]['delivery_DT'].date()

    if from_date:
        from_DT = from_date
    else:
        from_DT = date(year=2000, month=1, day=1)

    if to_date:
        to_DT = to_date + timedelta(days=1)
    else:
        to_DT = datetime.now().date() + timedelta(days=1)

    chart_data_Dict = OrderedDict({
        str(from_DT + timedelta(n)): {
            'sales_count': 0,
            'sales_sum': 0,
            'paid_sum': 0,
            'paid_cash': 0,
            'paid_invoice': 0
        } for n in range(int((to_DT - from_DT).days) + 1)
    })


    objs_i = 0
    while objs_i < len(objs):
        obj_i = objs[objs_i]

        # if separate_managers_sales_by_link_in_order:


        if not 'sales_count' in  obj_i:
            obj_i['sales_count'] = 0
        if not 'sales_sum' in  obj_i:
            obj_i['sales_sum'] = 0
        if not 'paid_sum' in  obj_i:
            obj_i['paid_sum'] = 0
        if not 'receipts_sum' in  obj_i:
            obj_i['receipts_sum'] = 0
        if not 'receipts_count' in  obj_i:
            obj_i['receipts_count'] = 0
        # # if not 'top_sales_80' in  obj_i:
        # # обнуляем все при каждой итерации
        #  obj_i['top_sales_80'] = ''
        #  obj_i['manager_top_sales_80'] = ''

        # if  obj_i['id'] == 657:
        #     print('!')

        obj_orders = list(filter(lambda item: item['manager_obj__id'] ==  obj_i['id'], orders))
        cash_orders = list(filter(lambda item: item['pay_type'] == 'cash', obj_orders))

        obj_pays = list(filter(lambda item: item['manager__id'] ==  obj_i['id'], pays))

        obj_receipts = list(filter(lambda item: item['manager_obj__id'] ==  obj_i['id'], receipts))
        cash_receipts = list(filter(lambda item: item['pay_type'] == 'cash' and item['receipts_sum'], obj_receipts))

        if obj_orders:
             obj_i['sales_sum'] += round(sum(item['sales_sum'] for item in obj_orders if item['sales_sum']), 2)
             obj_i['sales_count'] += round(sum(item['sales_count'] for item in obj_orders if item['sales_count']), 2)
        if cash_orders:
            # добавляем в оплаты кэшевые операции потому как они отсутствуют в платежах
             obj_i['paid_sum'] += round(sum(item['paid_sum'] for item in cash_orders if item['paid_sum']), 2)

        # if  obj_i['id'] == 1199:
        #     print('!')

        if obj_receipts:
             obj_i['receipts_sum'] += round(
                sum(item['receipts_sum'] for item in obj_receipts if item['receipts_sum']), 2)
             obj_i['receipts_count'] += round(
                sum(item['receipts_count'] for item in obj_receipts if item['receipts_count']), 2)

             obj_i['sales_sum'] -=  obj_i['receipts_sum']
             obj_i['sales_count'] -=  obj_i['receipts_count']

        if cash_receipts:
            # минусуем из оплат кэшевые операции потому как возвраты
            obj_i['paid_sum'] -= round(sum(item['receipts_sum'] for item in cash_receipts if item['receipts_sum']), 2)

        if obj_pays:
            obj_i['paid_sum'] += round(sum(item['sum_pay_byn'] for item in obj_pays if item['sum_pay_byn']), 2)

        obj_i['indicative_sales'] = round(( obj_i['sales_sum'] + obj_i['paid_sum']) / 2, 2)

        required_del_client = False
        if stat_kwargs:
            if stat_kwargs and 'sales_count__gte' in stat_kwargs and stat_kwargs['sales_count__gte'] and \
                    objs[objs_i][
                        'sales_count'] < float(stat_kwargs['sales_count__gte']):
                required_del_client = True
            elif stat_kwargs and 'sales_count__lte' in stat_kwargs and stat_kwargs['sales_count__lte'] and \
                    objs[objs_i][
                        'sales_count'] > float(stat_kwargs['sales_count__lte']):
                required_del_client = True
            elif stat_kwargs and 'sales_sum__gte' in stat_kwargs and stat_kwargs['sales_sum__gte'] and objs[objs_i][
                'sales_sum'] < float(stat_kwargs['sales_sum__gte']):
                required_del_client = True
            elif stat_kwargs and 'sales_sum__lte' in stat_kwargs and stat_kwargs['sales_sum__lte'] and objs[objs_i][
                'sales_sum'] > float(stat_kwargs['sales_sum__lte']):
                required_del_client = True

        # if 'months_count' in kwargs:
        #      obj_i['middle_sum_for_month'] = round( obj_i['indicative_sales'] / kwargs['months_count'], 2)
        # # else:
        # #     print('!')

        if required_del_client:
            del objs[objs_i]
        else:
            objs_i += 1

    msg = 'managers_sales_by_period_n_regions finish - {0} (processing time = {1}<br>---------------<br><br>'.format(
        str(datetime.now()),
        str(datetime.now() - log_begin_DT)
    )
    print(msg)

    return objs, chart_data_Dict