import datetime
from itertools import groupby
from operator import attrgetter

from NEMO.models import EmailNotificationType
from NEMO.typing import QuerySetType
from NEMO.utilities import (
    BasicDisplayTable,
    format_datetime,
    send_mail,
    get_email_from_settings,
    EmailCategory,
    quiet_int,
    export_format_datetime,
)
from NEMO.views.pagination import SortedPaginator
from django.contrib.auth.decorators import login_required, permission_required
from django.db.models import Q
from django.http import HttpResponse
from django.shortcuts import render
from django.views.decorators.http import require_GET

from NEMO_billing.institution_agreements.customization import InstitutionAgreementCustomization
from NEMO_billing.institution_agreements.models import InstitutionAgreement
from NEMO_billing.models import CoreFacility


@login_required
@permission_required("institution_agreements.view_institutionagreement", raise_exception=True)
def institution_agreements(request):
    institution_agreement_list = InstitutionAgreement.objects.all()
    page = SortedPaginator(institution_agreement_list, request, order_by="-start_date").get_current_page()
    core_facilities_exist = CoreFacility.objects.exists()

    if bool(request.GET.get("csv", False)):
        return export_institution_agreements(institution_agreement_list.order_by("-start_date"))

    return render(
        request, "institution_agreements.html", {"page": page, "core_facilities_exist": core_facilities_exist}
    )


def get_institution_agreements_table_display(institution_agreement_list) -> BasicDisplayTable:
    table = BasicDisplayTable()
    table.headers = [
        ("agreement_id", "ID"),
        ("name", "Name"),
        ("institution", "Institution"),
        ("core_facilities", "Core Facilities"),
        ("start_date", "Start"),
        ("expiration_date", "Expiration"),
        ("reminder_date", "Reminder date"),
        ("point_of_contact", "Point of Contact"),
        ("documents", "Documents"),
    ]
    for institution_agreement in institution_agreement_list:
        table.add_row(
            {
                "agreement_id": institution_agreement.agreement_id,
                "name": institution_agreement.name,
                "institution": institution_agreement.institution.name,
                "core_facilities": ", ".join([cf.name for cf in institution_agreement.core_facilities.all()]),
                "start_date": (
                    format_datetime(institution_agreement.start_date, "SHORT_DATE_FORMAT")
                    if institution_agreement.start_date
                    else ""
                ),
                "expiration_date": (
                    format_datetime(institution_agreement.expiration_date, "SHORT_DATE_FORMAT")
                    if institution_agreement.expiration_date
                    else ""
                ),
                "reminder_date": (
                    format_datetime(institution_agreement.reminder_date, "SHORT_DATE_FORMAT")
                    if institution_agreement.reminder_date
                    else ""
                ),
                "point_of_contact": f"{institution_agreement.point_of_contact_name} ({institution_agreement.point_of_contact_email})",
                "documents": "\n".join(
                    [doc.full_link() for doc in institution_agreement.institutionagreementdocuments_set.all()]
                ),
            }
        )
    return table


def export_institution_agreements(institution_agreements_list: QuerySetType[InstitutionAgreement]):
    table = get_institution_agreements_table_display(institution_agreements_list)
    filename = f"service_agreement_{export_format_datetime()}.csv"
    response = table.to_csv()
    response["Content-Disposition"] = f'attachment; filename="{filename}"'
    return response


def get_email_reminder_target_agreements():
    today = datetime.date.today()
    expiration_reminder_days = InstitutionAgreementCustomization.get("expiration_reminder_days")

    query = Q(reminder_date=today)
    if expiration_reminder_days:
        days = quiet_int(expiration_reminder_days, -1)
        if days >= 0:
            expires_in = today + datetime.timedelta(days=days)
            query |= Q(reminder_date__isnull=True, expiration_date=expires_in)

    return InstitutionAgreement.objects.filter(query)


@login_required
@permission_required("NEMO.trigger_timed_services", raise_exception=True)
@require_GET
def email_institution_agreements_reminders(request):
    return send_institution_agreements_email_reminders()


def send_institution_agreements_email_reminders():
    target_agreements = get_email_reminder_target_agreements().select_related("owner").order_by("owner__id")
    for owner, items in groupby(target_agreements, key=attrgetter("owner")):
        table = get_institution_agreements_table_display(list(items))
        to_emails = owner.get_emails(EmailNotificationType.BOTH_EMAILS)
        expiration_reminder_cc = InstitutionAgreementCustomization.get("expiration_reminder_cc")
        cc_emails = [e for e in expiration_reminder_cc.split(",") if e]
        if table and table.rows:
            message = "Hello,<br><br>\n\n"
            message += f"This email is a reminder to start the renewal process for the following Service Agreements:<br><br>\n\n"
            message += basic_table_to_html(table)
            subject = "Service Agreements renewal reminder"
            send_mail(
                subject=subject,
                content=message,
                from_email=get_email_from_settings(),
                to=to_emails,
                cc=cc_emails,
                email_category=EmailCategory.TIMED_SERVICES,
            )
    return HttpResponse()


def basic_table_to_html(table: BasicDisplayTable) -> str:
    style = ' style="padding: 5px; border: 1px solid black"'
    result = '<table style="border-collapse: collapse"><thead><tr>'
    for header in table.flat_headers():
        result += f"<th {style}>{header.capitalize()}</th>"
    result += "</tr></thead><tbody>"
    for row in table.rows:
        result += "<tr>"
        for cell_value in [row.get(key, "") for key, display_value in table.headers]:
            result += f"<td {style}>{cell_value or ''}</td>"
        result += "</tr>"
    result += "</tbody></table>"
    return result
