from datetime import datetime
from django.db.models.functions import Lower
from functools import wraps
from django.conf import settings
import requests
from app.entities import models
from datetime import timedelta
from django.db.models import Q
from dateutil import parser


# EMAIL = settings.EMAIL
# ACCOUNTS = settings.ACCOUNTS
# GROUPS = settings.GROUPS
# COMPANIES = settings.COMPANIES
# ALLOWED_COMPANY = settings.ALLOWED_COMPANY
# CR_FRONT_LINK = settings.CR_FRONT_LINK

# NOTIFICATION = settings.NOTIFICATION


def get_group_details(group_no):
    return requests.get(f'{GROUPS}?group_no={group_no}').json()['results'][0]


def get_companies_details(slug):
    return requests.get(f'{COMPANIES}?slug={slug}').json()['results'][0]


def get_account_details(id_number):
    return requests.get(f'{ACCOUNTS}?id_number={id_number}').json()['results'][0]


def get_allowed_company(id_number):
    return requests.get(f'{ALLOWED_COMPANY}?id_number={id_number}')


class QuerySetHelper:

    @staticmethod
    def Sort(context):
        sort_field = context.request.query_params.get('sort_field')
        sort_order = context.request.query_params.get('sort_order')
        if sort_field and sort_order:
            if sort_order.lower() == 'asc':
                context.queryset = context.queryset.order_by(sort_field)
            else:
                context.queryset = context.queryset.order_by(f"-{sort_field}")
        return context.queryset

    @staticmethod
    def Search(context):
        search_field = context.request.query_params.get('search-field')
        search_key = context.request.query_params.get('search-key')
        if search_field and search_key:
            context.queryset = context.queryset(
                __raw__={f"{search_field}" : {"$regex" : f".*{search_key.lower()}.*"}}
            )
        return context.queryset
    
    @staticmethod
    def SearchDynamic(base_queryset,
                      ):
        search_field = context.request.query_params.get('search-field')
        search_key = context.request.query_params.get('search-key')
        if search_field and search_key:
            context.queryset = context.queryset(
                __raw__={f"{search_field}" : {"$regex" : f".*{search_key.lower()}.*"}}
            )
        return context.queryset

        # if self.request.query_params.get('search'):
        #     search_key = self.request.query_params.get('search')
        
        #     self.queryset = self.queryset.filter(
        #         Q(requested_to_template_name__icontains=search_key.lower()) |
        #         Q(requested_to_template_id__icontains=search_key.lower())
        #     )

        # self.queryset = QuerySetHelper.Sort(self)

    @staticmethod
    def Filter(context):
        if int(len(context.request.query_params)) > 0:
            filtering_kwargs = {}
            with_params = []
            common_params = (
                'page', 'page-size', 'page_size', 'sort_order', 'sort_field'
            )
            for field, value in context.request.GET.items():
                filtering_kwargs = {}
                if value and field.lower() not in common_params:
                    filtering_kwargs[field] = {"$regex" : f".*{value.lower()}.*"}
                    filtering_kwargs[field] = {"$regex" : f".*{value}.*"}
                    # filtering_kwargs[field] = {"$regex" : f".*{value.lower()}.*"}
                    with_params.append(filtering_kwargs)
                    raw_query = {"$or": with_params}
                    context.queryset = context.queryset(__raw__=raw_query)
        return context.queryset


def ApproverStatus(status):
    choices = ["pending", "rejected", "approved", "completed", "cancelled", 'acknowledged', 'accepted']
    if status not in choices:
        return False
    else:
        return True


def number_generator(prefix, id):
    date = '{:%Y%m%d}'.format(datetime.now())
    id_num = '{:07}'.format(id)
    autogenerated_no = prefix + '-' + date + '-' + id_num

    return autogenerated_no


def logged_user(self):
    return self.request.META.get('HTTP_ACCOUNT_NO')


def receiver_body(
    sender_account_no, receiver_account_no,
    email_code, email_recipient,
    app, sent, name, routing_level,
    status, cr_number, cr_name,
    company_requestedto,
    department_requestedto,
    priority_level, url
):
    receiver_data = {
        "sender_account_no": sender_account_no,
        "receiver_account_no": receiver_account_no,
        "email_code": email_code,
        "email_recipient": email_recipient,
        "app": app,
        "sent": "False",
        "name": name,
        "routing_level": routing_level,
        "status": status,
        "cr_number": cr_number,
        "cr_name": cr_name,
        "company_requestedto": company_requestedto,
        "department_requestedto": department_requestedto,
        "priority_level": priority_level,
        "url": url
    }

    return receiver_data


def get_template_instance(form_code):
    template_instance = models.ChangeRequestFormHeader.objects.filter(
        Q(form_code=form_code) &
        Q(deleted_at=None)
    ).first()
    return template_instance


def send_notification(
    form_code, cr_number, user_id_number,
    user_name, message, app,
    sender_id_number, sender_name
):
    notification_data = {
        "slug": form_code,
        "change_request_template_code": cr_number,
        # (OPENING TAG) receiver credential
        "account_no": user_id_number,
        "user": user_name,
        # (CLOSING TAG) receiver credential
        "notif_type": "ACTIVITY",
        "message": message,
        "is_read": False,
        "app": app,
        "sender_account_no": sender_id_number,
        "createdby": sender_name
    }
    notification = requests.post(NOTIFICATION, data=notification_data)

    # return notification.status
    return notification

def send_mail_vendor(receiver, 
                     form_code, 
                     delegation, 
                     msg, 
                     action, 
                     code, 
                     remarks,
                     routing_level):
    app = 'cms'
    cr_link = f'{CR_FRONT_LINK}/{form_code}'
    template_instance = get_template_instance(form_code)

    cr_number = template_instance.requested_to_template_id
    template_name = template_instance.requested_to_template_name
    requested_to_company = template_instance.requested_to_company
    requested_to_department = template_instance.requested_to_department
    requested_by_user = template_instance.requested_by_user
    created = template_instance.created
    requested_to_priority = template_instance.requested_to_priority

    vendor_instance = models.ChangeRequestFormApprovers.objects.filter(
        Q(delegation="Vendor/Implementor") &
        Q(form_code=form_code)
    ).first()

    # receiver details
    vendor = get_account_details(vendor_instance.user)
    requestor_name = vendor['name']
    requestor_email = vendor['email']
    requestor_account_id = vendor['id_number']

    # sender details
    sender_instance = get_account_details(receiver)
    sender_account_username = sender_instance['username']
    sender_account_id = sender_instance['id_number']
    sender_name = sender_instance['name']

    group = get_group_details(requested_to_department)
    group_name = group['name']

    company = get_companies_details(requested_to_company)
    company_name = company['name']

    container = receiver_body(
        sender_account_id, requestor_account_id, code,
        requestor_email, app, "False", requestor_name, routing_level,
        action, cr_number, template_name, company_name, group_name,
        requested_to_priority, cr_link
    )

    if action.lower() == 'rejected':
        new_body = {"rejected_by": requestor_name,
                    "remarks": remarks}
    elif action.lower() == 'accepted':
        new_body = {"approved_by": requestor_name}
    
    data = {**container, **new_body}
    email_status = requests.post(EMAIL, data=data)

    message = f"{sender_name} {msg} ({template_name})"

    send_notification(
        form_code, cr_number,
        requestor_account_id, requestor_name,
        message, app,
        sender_account_id, sender_account_username
    )


def send_mail_requestor(receiver, 
                        form_code, 
                        delegation, 
                        msg, 
                        action, 
                        code, 
                        remarks,
                        routing_level):

    cr_link = f'{CR_FRONT_LINK}/{form_code}'
    template_instance = get_template_instance(form_code)
    app = 'cms'
    
    cr_number = template_instance.requested_to_template_id
    template_name = template_instance.requested_to_template_name
    requested_to_company = template_instance.requested_to_company
    requested_to_department = template_instance.requested_to_department
    requested_by_user = template_instance.requested_by_user
    created = template_instance.created
    requested_to_priority = template_instance.requested_to_priority
    
    # receiver details  --------------------------------------------------
    requestor_instance = get_account_details(requested_by_user)
    requestor_name = requestor_instance['name']
    requestor_email = requestor_instance['email']
    requestor_account_id = requestor_instance['id_number']

    # sender details    --------------------------------------------------
    sender_instance = get_account_details(receiver)
    sender_account_username = sender_instance['username']
    sender_account_id = sender_instance['id_number']
    sender_name = sender_instance['name']

    group = get_group_details(requested_to_department)
    group_name = group['name']

    company = get_companies_details(requested_to_company)
    company_name = company['name']

    data = receiver_body(
        sender_account_id, requestor_account_id, code,
        requestor_email, app, "False", requestor_name, routing_level,
        action, cr_number, template_name, company_name, group_name,
        requested_to_priority, cr_link
    )
    
    if action.lower() == 'approved':
        new_body = {"approved_by": sender_name}
    elif action.lower() == 'rejected':
        new_body = {"rejected_by": sender_name,
                    "remarks": remarks}
    elif action.lower() == 'completed':
        new_body = {"completed_by": sender_name}
    elif action.lower() == 'acknowledged':
        new_body = {"acknowledge_by": sender_name}

    data = {**data, **new_body}

    email_status = requests.post(EMAIL, data=data)

    message = f"{sender_name} {msg} ({template_name})"

    notif = send_notification(
        form_code, cr_number,
        requestor_account_id, requestor_name,
        message, app,
        sender_account_id, sender_account_username
    )


def next_appover_email(receiver, form_code, delegation, msg, action, code):
    cr_link = f'{CR_FRONT_LINK}/{form_code}'
    template_instance = get_template_instance(form_code)
    app = 'cms'

    cr_number = template_instance.requested_to_template_id
    template_name = template_instance.requested_to_template_name
    requested_to_company = template_instance.requested_to_company
    requested_to_department = template_instance.requested_to_department
    requested_by_user = template_instance.requested_by_user
    created = template_instance.created
    requested_to_priority = template_instance.requested_to_priority

    # for rec in receiver:
    # receiver details
    # if action == 'initial':    
    receiver_instance = get_account_details(receiver)
    # else:
    #     receiver_instance = get_account_details(receiver.user)

    receiver_name = receiver_instance['name']
    receiver_email = receiver_instance['email']
    receiver_account_id = receiver_instance['id_number']

    # sender details
    sender_instance = get_account_details(requested_by_user)
    sender_account_username = sender_instance['username']
    sender_account_id = sender_instance['id_number']
    sender_name = sender_instance['name']

    group = get_group_details(requested_to_department)
    group_name = group['name']

    company = get_companies_details(requested_to_company)
    company_name = company['name']
    
    data = receiver_body(
        sender_account_id, receiver_account_id, code,
        receiver_email, app, "False", receiver_name, 1,
        "Pending", cr_number, template_name, company_name, group_name,
        requested_to_priority, cr_link
    )

    email_status = requests.post(EMAIL, data=data)

    print(email_status)
    print("next_appover 3")

    message = f"{sender_name} {msg} ({template_name})"

    notif = send_notification(
        form_code, cr_number,
        receiver_account_id, receiver_name,
        message, app,
        sender_account_id, sender_account_username
    )

    return True


def cancel_overdue(request):
    date_submitted = datetime.now()
    requestor = request.data['requested_by_user']
    requestor = requests.get(f'{ACCOUNTS}{requestor}/')
    requestor = requestor.json()['results']

    cancel_date = date_submitted + timedelta(days=30)
    cancel_date = cancel_date.strftime('%Y-%m-%d 00:00:00.000')

    request.data['date_submitted'] = date_submitted
    request.data['cancel_date'] = cancel_date

    email_content_cancel = {
        "sender_account_no": requestor['id_number'],
        "receiver_account_no": requestor['id_number'],
        "email_code": "RMS-CRCANCELLED",
        "email_recipient": requestor['email'],
        "app": "CMS",
        "sent": "False",
        "name": requestor['name'],
        "status": "Pending",
        "auto_cancel_date": cancel_date,
        "cr_number": request.data['requested_to_template_id'],
        "cr_name": request.data['requested_to_template_name'],
        "company_requestedto": request.data['requested_to_company'],
        "department_requestedto": request.data['requested_to_department'],
        "priority_level": request.data['requested_to_priority'],
        "url": "http://devweb.rms.oneberrysystem.com/login"
    }

    exist_cancel_template = models.CancelDateCR.objects.filter(
        cr_number=request.data['requested_to_template_id']
    )
    if exist_cancel_template:
        exist_cancel_template.delete()

    models.CancelDateCR.objects.create(
        cr_number=request.data['requested_to_template_id'],
        trigger_date=cancel_date,
        email_content=email_content_cancel
    )

    requested_to_target_date = parser.parse(
        request.data['requested_to_target_date']
    )

    email_content_cancel['email_code'] = "RMS-CROVERDUE"
    email_content_cancel['target_date'] = requested_to_target_date

    overdue = requested_to_target_date + timedelta(days=30)
    overdue = overdue.strftime('%Y-%m-%d 00:00:00.000')

    models.TargetDateOverdue.objects.create(
        cr_number=form_code,
        trigger_date=overdue,
        email_content=email_content_cancel
    )
    return True
