from outils.common_imports import *
from outils.for_view_imports import *
from outils.common import Verification

from shifts.models import CagetteShift
from members.models import CagetteMember

# working_state = ['up_to_date', 'alert', 'exempted', 'delay', 'suspended']
state_shift_allowed = ["up_to_date", "alert", "delay"]

tz = pytz.timezone("Europe/Paris")

def dateIsoUTC(myDate):
    tDate = tz.localize(datetime.datetime.strptime(myDate, '%Y-%m-%d %H:%M:%S'))
    return tDate.isoformat()

def home(request, partner_id, hashed_date):
    import hashlib
    cs = CagetteShift()
    partnerData = cs.get_data_partner(partner_id)

    md5_calc = hashlib.md5(partnerData['create_date'].encode('utf-8')).hexdigest()
    if (md5_calc == hashed_date):
        # if not request.session.get('odoo_token', False):
        #     import uuid
        #     request.session['odoo_token'] = uuid.uuid4().hex
        #     request.session.modified = True
        # Ne fonctionne pas !!! Les données de sessions sont perdues à la connexion suivante (ajax : voir cross domain cookies
        if len(partnerData) > 0:
            partnerData['verif_token'] = md5_calc
            if len(partnerData['leave_ids']) > 0:
                listLeave = cs.get_leave(int(partner_id))
                if len(listLeave) > 0:
                    partnerData["is_leave"] = True
                    partnerData["leave_start_date"] = listLeave[0]["start_date"]
                    partnerData["leave_stop_date"] = listLeave[0]["stop_date"]

            # Error case encountered from Odoo: member in delay state and last extension is over -> member is suspended
            try:
                if partnerData['cooperative_state'] == "delay" and datetime.datetime.strptime(partnerData['date_delay_stop'], '%Y-%m-%d') < datetime.datetime.now():
                    partnerData['cooperative_state'] = "suspended"
            except:
                pass

            if partnerData['cooperative_state'] in state_shift_allowed:
                # domain = "127.0.0.1"
                domain = getattr(settings, 'EMAIL_DOMAIN', 'lacagette-coop.fr')
                days_to_hide = "0"
                if hasattr(settings, 'SHIFT_EXCHANGE_DAYS_TO_HIDE'):
                    days_to_hide = settings.SHIFT_EXCHANGE_DAYS_TO_HIDE
                context = {'title': 'Calendrier', "partnerData": partnerData,
                           'daysToHide': days_to_hide,
                           'SHIFT_INFO': settings.SHIFT_INFO,
                           'PB_INSTRUCTIONS': settings.PB_INSTRUCTIONS,
                           'domain': domain}
                context['ADDITIONAL_INFO_SHIFT_PAGE'] = getattr(settings, 'ADDITIONAL_INFO_SHIFT_PAGE', '')
                if hasattr(settings, 'CALENDAR_NO_MORE_LINK'):
                    if settings.CALENDAR_NO_MORE_LINK is True:
                        context['calendarEventNoMoreLinks'] = True
                if hasattr(settings, 'CAL_INITIAL_VIEW'):
                    context['calInitialView'] = settings.CAL_INITIAL_VIEW
                    #  No effect with 3.9 version : TODO upgrade fullCalendar lib
                    #  Needs init calendar rewriting
                response = render(request, 'shifts/shift_exchange.html', context)
            else:
                context = {'title': 'Invitation', "partnerData": partnerData}
                if hasattr(settings, 'UNSUBSCRIBED_MSG'):
                    context['UNSUBSCRIBED_MSG'] = settings.UNSUBSCRIBED_MSG
                response = render(request, 'shifts/shift_states_not_allowed.html', context)

            # response.set_cookie('odoo_token', request.session.get('odoo_token', False) )
            return response
        else:
            return HttpResponseNotFound('<h1>Nothing to show !</h1>')
    else:
        return HttpResponseForbidden()


def _is_middled_filled_considered(reserved, max):
    """Added to fit with new LaCagette need. (based on num rather than %)."""
    answer = False
    toggle_num = 0
    try:
        toggle_num = int(getattr(settings, 'SHIFT_COLOR_TOGGLE_NUM', 0))
    except:
        coop_logger.warning("Wrong value for SHIFT_COLOR_TOGGLE_NUM : %s",
                            str(getattr(settings, 'SHIFT_COLOR_TOGGLE_NUM', 0))
                            )
    if toggle_num == 0:
        if int(reserved) / int(max) < 0.5:
            answer = True
    else:
        answer = int(reserved) <= toggle_num
    return answer


def get_list_shift_calendar(request, partner_id):
    cs = CagetteShift()
    [registerPartner, is_ftop] = cs.get_shift_partner(partner_id)

    use_new_members_space = getattr(settings, 'USE_NEW_MEMBERS_SPACE', False) 
    remove_15_minutes_at_shift_end = getattr(settings, 'REMOVE_15_MINUTES_AT_SHIFT_END', True)
    listRegisterPartner = []
    listMakeUpShift = []
    for v in registerPartner:
        listRegisterPartner.append(v['id'])
        if v['is_makeup']:
            listMakeUpShift.append(v['id'])

    start = request.GET.get('start')
    end = request.GET.get('end')
    listService = cs.get_shift_calendar(is_ftop, start, end)

    events = []
    for value in listService:
        if value['shift_type_id'][0] == 1 or getattr(settings, 'USE_STANDARD_SHIFT', True) is False:
            #  Standard ou volant si on n'utilise pas les services standards (config)
            l = set(value['registration_ids']) & set(listRegisterPartner)
            # if (int(value['seats_reserved']) == int(value['seats_max']) and len(l) > 0 ) or (int(value['seats_reserved']) < int(value['seats_max'])):
            if (int(value['seats_available']) > 0 or len(l) > 0 ):
                event = {}
                event["id"] = value['id']
                smax = int(value['seats_available']) + int(value['seats_reserved'])
 
                company_code = getattr(settings, 'COMPANY_CODE', '')
                title_prefix = ''
                if company_code != "lacagette" and len(value['address_id']) == 2 and ',' in value['address_id'][1]:
                    title_prefix = str(value['address_id'][1]).split(",")[1] + " --"
                elif company_code == "lacagette":
                    title_prefix = " - "

                event["title"] = title_prefix + str(value['seats_reserved']) + "/" + str(smax)


                event["start"] = dateIsoUTC(value['date_begin_tz'])

                datetime_object = datetime.datetime.strptime(value['date_end_tz'], "%Y-%m-%d %H:%M:%S") - datetime.timedelta(minutes=15)
                if remove_15_minutes_at_shift_end is True:
                    datetime_object -= datetime.timedelta(minutes=15)
                event["end"] = dateIsoUTC(datetime_object.strftime("%Y-%m-%d %H:%M:%S"))

                if len(l) > 0:
                    if use_new_members_space is True:
                        if set(value['registration_ids']) & set(listRegisterPartner) & set(listMakeUpShift):
                            event["classNames"] = ["shift_booked_makeup"]
                        else : 
                            event["classNames"] = ["shift_booked"]
                    else:
                        event["className"] = "shift_booked"
                    event["changed"] = False
                # elif int(value['seats_reserved']) == int(value['seats_max']):
                #     event["className"] = "shift_full"
                #     event["changed"] = False
                elif int(value['seats_reserved']) == 0:
                    if use_new_members_space is True:
                        event["classNames"] = ["shift_empty"]
                    else:
                        event["className"] = "shift_empty"
                    event["changed"] = True
                elif _is_middled_filled_considered(value['seats_reserved'], smax) is True:
                    if use_new_members_space is True:
                        event["classNames"] = ["shift_less_alf"]
                    else:
                        event["className"] = "shift_less_alf"
                    event["changed"] = True
                else:
                    if use_new_members_space is True:
                        event["classNames"] = ["shift_other"]
                    else:
                        event["className"] = "shift_other"
                    event["changed"] = True

                event["registration_ids"] = value['registration_ids']
                events.append(event)

    response = JsonResponse(events, safe=False)
    return response

def get_list_shift_partner(request, partner_id):
    cs = CagetteShift()
    [shiftData, is_ftop] = cs.get_shift_partner(partner_id)

    for value in shiftData:
        value['date_begin'] = value['date_begin'] + "Z"
        value['date_end'] = value['date_end'] + "Z"

    return JsonResponse(shiftData, safe=False)

def change_shift(request):
    if 'verif_token' in request.POST:
        if Verification.verif_token(request.POST.get('verif_token'), int(request.POST.get('idPartner'))) is True:

            cs = CagetteShift()

            if 'idNewShift' in request.POST and 'idOldShift' in request.POST:
                idOldShift = request.POST['idOldShift']
                listRegister = [int(request.POST['idRegister'])]
                data = {
                    "idPartner": int(request.POST['idPartner']),
                    "idShift": int(request.POST['idNewShift']),
                    "shift_type": request.POST['shift_type'],
                    "is_makeup": cs.shift_is_makeup(listRegister[0])
                }
                
                should_block_service_exchange = getattr(settings, 'BLOCK_SERVICE_EXCHANGE_24H_BEFORE', False)
                if should_block_service_exchange:
                    # Block change if old shift is to happen in less than 24 hours
                    now = datetime.datetime.now(tz)

                    old_shift = cs.get_shift(idOldShift)
                    day_before_old_shift_date_start = tz.localize(datetime.datetime.strptime(old_shift['date_begin_tz'], '%Y-%m-%d %H:%M:%S') - datetime.timedelta(hours=24))

                    if now > day_before_old_shift_date_start:
                        response = {'msg': "Old service in less than 24hours."}
                        return JsonResponse(response, status=400)

                if cs.is_shift_exchange_allowed(idOldShift, data["idShift"], data["shift_type"], data["idPartner"]) is False:
                    response = {'msg': "Not allowed to change shift"}
                    return JsonResponse(response, status=400)


                st_r_id = False
                #Insertion du nouveau shift
                try:
                    st_r_id = cs.set_shift(data)
                except Exception as e:
                    coop_logger.error("Change shift : %s, %s", str(e), str(data))
                if st_r_id:
                    listRegister = [int(request.POST['idRegister'])]

                    # Annule l'ancien shift
                    response = cs.cancel_shift(listRegister)

                    response = {'result': True}
                else:
                    response = {'msg': "Fail to create shift"}
                    return JsonResponse(response, status=500)
            else:
                response = {'msg': "Bad arguments"}
                return JsonResponse(response, status=400)
            return JsonResponse(response)
        else:
            return HttpResponseForbidden()
    else:
        return HttpResponseForbidden()

def affect_shift(request):
    if 'verif_token' in request.POST:
        if Verification.verif_token(request.POST.get('verif_token'), int(request.POST.get('idPartner'))) is True:
            cs = CagetteShift()
            if 'idShiftRegistration' in request.POST and 'affected_partner' in request.POST:
                #  if request is made by associated people, idPartner is it's id, not "master" res.partner
                #  it's will be handled in model's method (affect_shift)
                data = {
                    "idPartner": int(request.POST['idPartner']),
                    "idShiftRegistration": int(request.POST['idShiftRegistration']),
                    "affected_partner": request.POST['affected_partner'],
                }
                st_r_id = None
                try:
                    st_r_id = cs.affect_shift(data)
                except Exception as e:
                    coop_logger.error("affect shift : %s, %s", str(e), str(data))
                if st_r_id:
                    response = {'result': True}
                else:
                    response = {'msg': "Internal Error"}
                    return JsonResponse(response, status=500)
                return(JsonResponse({'result': True}))
            else:
                response = {'msg': "Bad args"}
                return JsonResponse(response, status=400)
        else:
            return HttpResponseForbidden()
    else:
        return HttpResponseForbidden()

def add_shift(request):
    if 'verif_token' in request.POST:
        if Verification.verif_token(request.POST.get('verif_token'), int(request.POST.get('idPartner'))) is True:
            cs = CagetteShift()

            if 'idNewShift' in request.POST and 'idPartner' in request.POST:
                partner_id = int(request.POST['idPartner'])
                id_shift = int(request.POST['idNewShift'])
                data = {
                    "idPartner": partner_id, 
                    "idShift": id_shift, 
                    "shift_type": request.POST['shift_type'],
                    "is_makeup": False
                }

                if 'is_makeup' in request.POST and request.POST['is_makeup'] == "1":
                    data['is_makeup'] = True

                if request.POST['shift_type'] == "ftop":
                    if cs.is_matching_ftop_rules(partner_id, id_shift) is True:
                        # Need to find out if a makeup has to be choosen
                        makeups_to_do = cs.get_member_makeups_to_do(partner_id)
                        if makeups_to_do != 0:
                            data['is_makeup'] = True

                    else:
                        response = {'msg': "FTOP rules not respected"}
                        return JsonResponse(response, status=422)
                
                #Insertion du nouveau shift
                st_r_id = False
                try:
                    st_r_id = cs.set_shift(data)
                except Exception as e:
                    coop_logger.error("Add shift : %s, %s", str(e), str(data))

                if st_r_id:
                    response = {'result': True}
                else:
                    response = {'result': False}

                # decrement makeups_to_do
                response["decrement_makeups"] = False
                if data['is_makeup'] is True:
                    try:
                        res_decrement = cs.decrement_makeups_to_do(int(request.POST['idPartner']))
                    except Exception as e:
                        coop_logger.error("Decrement makeups to do : %s, %s", str(e), str(data))

                    if res_decrement:
                        response["decrement_makeups"] = res_decrement
            else:
                response = {'result': False}
            return JsonResponse(response)
        else:
            return HttpResponseForbidden()
    else:
        return HttpResponseForbidden()

def cancel_shift(request):
    """ Annule une présence à un shift """
    if 'verif_token' in request.POST:
        partner_id = int(request.POST.get('idPartner'))
        if Verification.verif_token(request.POST.get('verif_token'), partner_id) is True:

            cs = CagetteShift()
            listRegister = [int(request.POST['idRegister'])]

            try:
                # decrement extra_shift_done if param exists
                if 'extra_shift_done' in request.POST:
                    response = cs.cancel_shift(listRegister, origin='memberspace extra shift done')
                    target = int(request.POST["extra_shift_done"]) - 1

                    # extra security
                    if target < 0:
                        target = 0

                    cm = CagetteMember(partner_id)
                    cm.update_extra_shift_done(target)
                else:
                    response = cs.cancel_shift(listRegister)

                return JsonResponse({"res" : 'response'})
            except Exception as e:
                return JsonResponse({"error" : str(e)}, status=500)
        else:
            return HttpResponseForbidden()
    else:
        return HttpResponseForbidden()

def request_delay(request):
    if 'verif_token' in request.POST:
        if Verification.verif_token(request.POST.get('verif_token'), int(request.POST.get('idPartner'))) is True:
            cs = CagetteShift()
            partner_id = int(request.POST['idPartner'])

            use_new_members_space = getattr(settings, 'USE_NEW_MEMBERS_SPACE', False) 
            if use_new_members_space is True:
                member_can_have_delay = cs.member_can_have_delay(int(request.POST.get('idPartner')))
                if member_can_have_delay is False:
                    res = { 'message' : 'delays limit reached'}
                    return JsonResponse(res, status=403)
            
            data = {
                "idPartner": partner_id,
                "start_date" : request.POST['start_date']
            }
            if ('extension_beginning' in request.POST):
                data['extension_beginning'] = request.POST['extension_beginning']
            duration = 28
            if ('duration' in request.POST):
                duration = int(request.POST['duration'])

            response = {'result': False}

            try:
                new_id = cs.create_delay(data, duration)
                if (new_id):
                    try:
                        cm = CagetteMember(partner_id)

                        # Add 0 pt to counter so odoo updates member status
                        data = {
                            'name': "Forcer l'entrée en délai",
                            'shift_id': False,
                            'type': "standard",
                            'partner_id': partner_id,
                            'point_qty': 0
                        }
                        cm.update_member_points(data)

                        data = {
                            'name': "Forcer l'entrée en délai",
                            'shift_id': False,
                            'type': "ftop",
                            'partner_id': partner_id,
                            'point_qty': 0
                        }
                        cm.update_member_points(data)
                    except Exception as e:
                        print(str(e))

                    response = {'result': True}
                else:
                    coop_logger.error("request delay : %s, %s", str(new_id), str(data))
                    return HttpResponseServerError()
            except Exception as e:
                coop_logger.error("request delay : %s, %s", str(e), str(data))
                return HttpResponseServerError()

            return JsonResponse(response)
        else:
            return HttpResponseForbidden()
    else:
        return HttpResponseForbidden()

def reset_members_positive_points(request):
    """Called by a cron script"""
    return JsonResponse({'res': CagetteShift.reset_members_positive_points()})

def get_test(request):
    cs = CagetteShift()

    fields = ['shift_ticket_ids', 'shift_type_id']  # res.partner
    cond = []
    # cond = [['partner_id','=',1522],['start_date','<',datetime.datetime.now().isoformat()],['stop_date','>',datetime.datetime.now().isoformat()]]
    # registerPartner = cs.get_test('shift.shift',cond,fields)
    registerPartner =  cs.get_shift_calendar(1018)  # cs.get_data_partner(1538)

    response = JsonResponse(registerPartner, safe=False)
    return response
    #return  HttpResponse(shiftData)

def get_list(request):
    cs = CagetteShift()

    fields = ['cooperative_state']  # res.partner
    cond = []
    registerPartner = cs.get_test('res.partner', cond, fields)
    liste = []
    for val in registerPartner:
        if val[fields[0]] not in liste:
            liste.append(val[fields[0]])

    return JsonResponse(liste, safe=False)

def get_current_cycle_week(request):
    cs = CagetteShift()
    return JsonResponse(cs.get_current_cycle_week_data(), safe=False)
