import calendar
from io import BytesIO

from openpyxl import Workbook
from openpyxl.styles import Alignment, Border, Font, PatternFill, Side
from openpyxl.utils import get_column_letter

BLUE_FILL = PatternFill(start_color="2F75B5", end_color="2F75B5", fill_type="solid")
HEADER_FONT = Font(name="Calibri", size=11, bold=True, color="FFFFFF")
DATA_FONT = Font(name="Calibri", size=10)
HEADER_ALIGN = Alignment(horizontal="center", vertical="center", wrap_text=True)
DATA_ALIGN = Alignment(horizontal="center", vertical="center", wrap_text=True)
RTL_ALIGN = Alignment(horizontal="right", vertical="center", wrap_text=True)
THIN = Side(style="thin")
THIN_BORDER = Border(left=THIN, right=THIN, top=THIN, bottom=THIN)

VERT_MERGE_HEADERS = [
    (2, "No."),
    (3, "رقم الشكوى"),
    (4, "رقم الملف"),
    (5, "جهة الشكوى"),
    (6, "الموقع"),
    (7, "القسم الرئيس"),
    (8, "القسم الفرعي"),
    (9, "تاريخ إستلام الشكوى"),
    (10, "المدخل"),
    (14, "رقم الجوال"),
    (15, "Time line"),
    (18, "Employee"),
    (23, "Employee"),
    (26, "Employee"),
    (27, "الوقت بين التحرير والارسال"),
    (30, "Employee"),
    (31, "الوقت بين اول ايميل والارسال"),
    (34, "Employee"),
    (35, "الوقت بين ثاني ايميل والاول"),
    (38, "Employee"),
    (39, "الوقت بين التصعيد والارسال"),
    (42, "Employee"),
    (43, "الوقت بين الاغلاق والارسال"),
    (46, "Employee"),
    (47, "الوقت بين المعالجة و الارسال"),
    (50, "الوقت بين الرد والارسال"),
    (51, "اسم الشخص المشتكى عليه"),
    (52, "موضوع الشكوى الأساسية"),
    (53, "الشكوى باختصار (عربي)"),
    (54, "الشكوى باختصار English"),
    (55, "توثيق تذكيرات للقسم"),
    (56, "تاريخ التذكير"),
    (57, "سبب تأخير القسم بالرد"),
    (58, "سبب تأخير اغلاق الشكوى خلال 72 ساعه"),
    (59, "الشخص المتأخر"),
    (60, "Satisfied/Dissatisfied"),
    (61, "الاجراء المتخذ من قبل القسم المعني"),
    (62, "نتيجة الاجراء المتخذ بعد التحقيق"),
    (63, "حلول واقتراحات"),
    (64, "Recommendation/Action plan"),
    (65, "Responsible Department"),
    (66, "The Rightful Side"),
    (67, "PR - Observations / Patient Supervisor"),
]

HORIZ_MERGE_HEADERS = [
    (11, 13, "MOH & CHI"),
    (16, 17, "إرسال نموذج الشكوى"),
    (19, 20, "تحرير الشكوى"),
    (21, 22, "تفعيل الشكوى"),
    (24, 25, "تم ارسال الشكوى"),
    (28, 29, "First Reminder Sent"),
    (32, 33, "Second Reminder Sent"),
    (36, 37, "Escalated"),
    (40, 41, "Closed"),
    (44, 45, "Resolved"),
    (48, 49, "تاريخ الرد"),
]

DATE_TIME_SUBS = {
    11: ("Date", "Time"),
    16: ("Date", "Time"),
    19: ("Date", "Time"),
    21: ("Date", "Time"),
    24: ("Date", "Time"),
    28: ("Date", "Time"),
    32: ("Date", "Time"),
    36: ("Date", "Time"),
    40: ("Date", "Time"),
    44: ("Date", "Time"),
    48: ("Date", "Time"),
}


def _dt(v):
    return v.date() if v else ""


def _tm(v):
    return v.strftime("%H:%M") if v else ""


def _write_headers(ws):
    cell = ws.cell(row=1, column=1, value="Week")
    cell.font = HEADER_FONT
    cell.fill = BLUE_FILL
    cell.alignment = HEADER_ALIGN
    cell.border = THIN_BORDER
    ws.merge_cells(start_row=1, start_column=1, end_row=2, end_column=1)

    for col, label in VERT_MERGE_HEADERS:
        cell = ws.cell(row=1, column=col, value=label)
        cell.font = HEADER_FONT
        cell.fill = BLUE_FILL
        cell.alignment = HEADER_ALIGN
        cell.border = THIN_BORDER
        ws.merge_cells(start_row=1, start_column=col, end_row=2, end_column=col)
        bc = ws.cell(row=2, column=col)
        bc.font = HEADER_FONT
        bc.fill = BLUE_FILL
        bc.border = THIN_BORDER

    for start_col, end_col, label in HORIZ_MERGE_HEADERS:
        cell = ws.cell(row=1, column=start_col, value=label)
        cell.font = HEADER_FONT
        cell.fill = BLUE_FILL
        cell.alignment = HEADER_ALIGN
        cell.border = THIN_BORDER
        ws.merge_cells(start_row=1, start_column=start_col, end_row=1, end_column=end_col)
        for c in range(start_col + 1, end_col + 1):
            bc = ws.cell(row=1, column=c)
            bc.font = HEADER_FONT
            bc.fill = BLUE_FILL
            bc.border = THIN_BORDER

        date_l, time_l = DATE_TIME_SUBS.get(start_col, ("Date", "Time"))
        dc = ws.cell(row=2, column=start_col, value=date_l)
        dc.font = HEADER_FONT
        dc.fill = BLUE_FILL
        dc.alignment = HEADER_ALIGN
        dc.border = THIN_BORDER
        tc = ws.cell(row=2, column=end_col, value=time_l)
        tc.font = HEADER_FONT
        tc.fill = BLUE_FILL
        tc.alignment = HEADER_ALIGN
        tc.border = THIN_BORDER


def _write_data_rows(ws, queryset):
    complaints = list(queryset.order_by("created_at"))
    if not complaints:
        return

    weeks = {}
    for idx, c in enumerate(complaints, 1):
        day = c.created_at.day
        if day <= 7:
            wk = 1
        elif day <= 15:
            wk = 2
        elif day <= 22:
            wk = 3
        elif day <= 28:
            wk = 4
        else:
            wk = 5
        weeks[idx] = wk

    row_num = 3
    current_week = None
    week_start_row = None

    for idx, c in enumerate(complaints, 1):
        wk = weeks[idx]

        if wk != current_week:
            if current_week is not None and week_start_row is not None and row_num - 1 > week_start_row:
                ws.merge_cells(start_row=week_start_row, start_column=1, end_row=row_num - 1, end_column=1)
            cell = ws.cell(row=row_num, column=1, value=f"Wk {wk}")
            cell.font = DATA_FONT
            cell.alignment = Alignment(horizontal="center", vertical="center")
            cell.border = THIN_BORDER
            current_week = wk
            week_start_row = row_num

        inv_dept = None
        for id_obj in c.involved_departments.all():
            if id_obj.is_primary:
                inv_dept = id_obj
                break
        if inv_dept is None and c.involved_departments.exists():
            inv_dept = c.involved_departments.first()

        satisfaction = ""
        if c.satisfaction:
            satisfaction = c.satisfaction.replace("_", " ").title()

        resolution_outcome = ""
        if c.resolution_outcome:
            resolution_outcome = c.resolution_outcome.replace("_", " ").title()

        vals = [
            idx,
            c.reference_number or "",
            c.file_number or "",
            c.source.name_en if c.source else (c.complaint_source_type or ""),
            c.department.name_en if c.department else "",
            c.domain.name_en if c.domain else "",
            c.category.name_en if c.category else "",
            c.created_at,
            c.created_by.get_full_name() if c.created_by else "",
            c.moh_reference_date, "", "",
            c.contact_phone or "",
            c.due_at,
            _dt(c.form_sent_at), _tm(c.form_sent_at),
            c.created_by.get_full_name() if c.created_by else "",
            _dt(c.created_at), _tm(c.created_at),
            _dt(c.activated_at), _tm(c.activated_at),
            c.assigned_to.get_full_name() if c.assigned_to else "",
            _dt(c.forwarded_to_dept_at), _tm(c.forwarded_to_dept_at),
            c.assigned_to.get_full_name() if c.assigned_to else "",
            "",
            _dt(c.reminder_sent_at), _tm(c.reminder_sent_at),
            "",
            "",
            _dt(c.second_reminder_sent_at), _tm(c.second_reminder_sent_at),
            "",
            "",
            _dt(c.escalated_at), _tm(c.escalated_at),
            "",
            "",
            _dt(c.closed_at), _tm(c.closed_at),
            c.closed_by.get_full_name() if c.closed_by else "",
            "",
            _dt(c.resolved_at), _tm(c.resolved_at),
            c.resolved_by.get_full_name() if c.resolved_by else "",
            "",
            _dt(c.response_date) if c.response_date else "", "",
            "",
            c.staff_name or "",
            c.complaint_subject or c.title or "",
            c.ai_brief_ar or "",
            c.ai_brief_en or "",
            inv_dept.response_notes if inv_dept else "",
            inv_dept.first_reminder_sent_at if inv_dept else "",
            inv_dept.delay_reason if inv_dept else c.explanation_delay_reason or "",
            c.delay_reason_closure or "",
            inv_dept.delayed_person if inv_dept else "",
            satisfaction,
            c.action_taken_by_dept or "",
            c.action_result or "",
            c.recommendation_action_plan or "",
            c.recommendation_action_plan or "",
            c.department.name if c.department else "",
            resolution_outcome,
            "",
        ]

        for col, val in enumerate(vals, 2):
            cell = ws.cell(row=row_num, column=col, value=val)
            cell.font = DATA_FONT
            cell.alignment = RTL_ALIGN if col in (53, 54, 61, 62, 63, 64) else DATA_ALIGN
            cell.border = THIN_BORDER

        row_num += 1

    if week_start_row and row_num - 1 > week_start_row:
        ws.merge_cells(start_row=week_start_row, start_column=1, end_row=row_num - 1, end_column=1)


def _set_col_widths(ws):
    ws.column_dimensions[get_column_letter(1)].width = 8
    ws.column_dimensions[get_column_letter(2)].width = 5
    for c in range(3, 68):
        w = 14
        if c in (9,):
            w = 16
        elif c in (52, 53, 54, 61, 62, 63, 64):
            w = 35
        elif c in (13, 15):
            w = 14
        ws.column_dimensions[get_column_letter(c)].width = w
    ws.freeze_panes = "C3"


def generate_complaint_monthly_excel(service):
    queryset = service._base_qs().prefetch_related(
        "involved_departments__department",
    )
    month_label = f"{service.year}-{service.month:02d}"
    month_abbr = calendar.month_abbr[service.month].upper()

    wb = Workbook()
    ws = wb.active
    ws.title = month_abbr

    _write_headers(ws)
    _write_data_rows(ws, queryset)
    _set_col_widths(ws)

    buf = BytesIO()
    wb.save(buf)
    buf.seek(0)
    return buf
