import calendar
from io import BytesIO

from openpyxl import Workbook
from openpyxl.chart import BarChart, LineChart, PieChart, Reference
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")
GREEN_FILL = PatternFill(start_color="00B050", end_color="00B050", fill_type="solid")
HEADER_FONT = Font(name="Calibri", size=11, bold=True, color="FFFFFF")
BOLD_FONT = Font(name="Calibri", size=11, bold=True)
DATA_FONT = Font(name="Calibri", size=11)
PCT_FMT = "0.0%"
NUM_FMT = "0.0"
THIN = Side(style="thin")
BORDER_ALL = Border(left=THIN, right=THIN, top=THIN, bottom=THIN)
CENTER = Alignment(horizontal="center", vertical="center", wrap_text=True)
RIGHT_ALIGN = Alignment(horizontal="right", vertical="center")


def _style_header(ws, row, col, value):
    cell = ws.cell(row=row, column=col, value=value)
    cell.font = HEADER_FONT
    cell.fill = BLUE_FILL
    cell.alignment = CENTER
    cell.border = BORDER_ALL
    return cell


def _style_data(ws, row, col, value, fmt=None):
    cell = ws.cell(row=row, column=col, value=value)
    cell.font = DATA_FONT
    cell.alignment = CENTER
    cell.border = BORDER_ALL
    if fmt:
        cell.number_format = fmt
    return cell


def _style_bold(ws, row, col, value, fmt=None):
    cell = ws.cell(row=row, column=col, value=value)
    cell.font = BOLD_FONT
    cell.border = BORDER_ALL
    cell.alignment = CENTER
    if fmt:
        cell.number_format = fmt
    return cell


def _strip_tz(dt):
    if dt is None:
        return None
    return dt.replace(tzinfo=None)


def _write_all_quarters_sheet(wb, service):
    rows = service.get_all_complaints_raw()
    ws = wb.create_sheet("ALL Quarters")

    headers = [
        "Week", "#", "Reference", "Source", "Location", "Department", "Domain",
        "Created At", "Entered By", "Timeline",
        "Form Sent", "Activated At", "Assigned To",
        "Sent To Dept", "Time Entry→Send",
        "First Reminder", "Time 1st Reminder→Send",
        "Second Reminder", "Escalated At",
        "Closed At", "Resolved At",
        "Processing Hours", "Response Date", "Status", "Satisfaction",
    ]
    for i, h in enumerate(headers, 1):
        _style_header(ws, 1, i, h)

    for idx, r in enumerate(rows, 2):
        week_num = (r["created_at"].day - 1) // 15 + 1
        week_label = "1st Half" if r["created_at"].day <= 15 else "2nd Half"
        col = 1
        _style_data(ws, idx, col, f"{week_label} of the month, From {'1' if r['created_at'].day <= 15 else '16'} to {'15' if r['created_at'].day <= 15 else str(calendar.monthrange(r['created_at'].year, r['created_at'].month)[1])}"); col += 1
        _style_data(ws, idx, col, idx - 1); col += 1
        _style_data(ws, idx, col, r["reference"]); col += 1
        _style_data(ws, idx, col, r["source"]); col += 1
        _style_data(ws, idx, col, r["location"]); col += 1
        _style_data(ws, idx, col, r["department"]); col += 1
        _style_data(ws, idx, col, r["domain"]); col += 1
        _style_data(ws, idx, col, _strip_tz(r["created_at"])); col += 1
        _style_data(ws, idx, col, r["entered_by"]); col += 1
        _style_data(ws, idx, col, r["timeline_bucket"]); col += 1
        _style_data(ws, idx, col, _strip_tz(r["form_sent_at"])); col += 1
        _style_data(ws, idx, col, _strip_tz(r["activated_at"])); col += 1
        _style_data(ws, idx, col, r["assigned_to"]); col += 1
        _style_data(ws, idx, col, _strip_tz(r["sent_at"])); col += 1
        _style_data(ws, idx, col, r["time_entry_to_send"]); col += 1
        _style_data(ws, idx, col, _strip_tz(r["first_reminder"])); col += 1
        _style_data(ws, idx, col, r["time_first_reminder_to_send"]); col += 1
        _style_data(ws, idx, col, _strip_tz(r.get("second_reminder"))); col += 1
        _style_data(ws, idx, col, _strip_tz(r["escalated_at"])); col += 1
        _style_data(ws, idx, col, _strip_tz(r["closed_at"])); col += 1
        _style_data(ws, idx, col, _strip_tz(r["resolved_at"])); col += 1
        _style_data(ws, idx, col, r["processing_hours"]); col += 1
        _style_data(ws, idx, col, r["response_date"]); col += 1
        _style_data(ws, idx, col, r["status"]); col += 1
        _style_data(ws, idx, col, r["satisfaction"]); col += 1

    for c in range(1, len(headers) + 1):
        ws.column_dimensions[get_column_letter(c)].width = 18
    ws.column_dimensions["B"].width = 8
    ws.column_dimensions["C"].width = 20


def _write_kpi_sheet(wb, service):
    kpi = service.get_kpi_data()
    satisfaction = service.get_satisfaction_data()
    moh_kpi = service.get_moh_kpi_data()
    months = service.active_month_labels
    active_months = service.active_months
    total_col = 2 + len(months)

    def _kpi_row(ws, row, label, get_val, total_val, is_pct=False):
        _style_data(ws, row, 1, label)
        for i, m in enumerate(active_months):
            v = get_val(m)
            fmt = PCT_FMT if is_pct else None
            _style_data(ws, row, 2 + i, v, fmt)
        _style_data(ws, row, total_col, total_val, PCT_FMT if is_pct else None)

    blocks = [
        {
            "kpi_label": "KPI #1",
            "header": "Numerator/Denominator",
            "rows": [
                ("Total Number of Closed Complaints", lambda m: kpi["months"][m]["closed"], kpi["totals"]["closed"]),
                ("Total Number of Complaints", lambda m: kpi["months"][m]["total"], kpi["totals"]["total"]),
                ("Result (%)", lambda m: kpi["months"][m]["resolution_rate"], kpi["totals"]["resolution_rate"], True),
            ],
        },
        {
            "kpi_label": "KPI #2",
            "header": "Numerator/Denominator",
            "rows": [
                ("Number of Complaints Resolved Within 72 Hours", lambda m: kpi["months"][m]["resolved_72h"], kpi["totals"]["resolved_72h"]),
                ("Total Number of Complaints", lambda m: kpi["months"][m]["total"], kpi["totals"]["total"]),
                ("Result (%)", lambda m: kpi["months"][m]["resolved_72h_rate"], kpi["totals"]["resolved_72h_rate"], True),
            ],
        },
        {
            "kpi_label": "KPI #3",
            "header": "Satisfaction Rate",
            "rows": [
                ("Number\u00a0of\u00a0Satisfied\u00a0Responses", lambda m: satisfaction["months"][m]["satisfied"], satisfaction["totals"]["satisfied"]),
                ("Total Number of Patient Surveyed (Responses)", lambda m: satisfaction["months"][m]["surveyed"], satisfaction["totals"]["surveyed"]),
                ("Result (%)", lambda m: satisfaction["months"][m]["rate"], satisfaction["totals"]["rate"], True),
            ],
        },
        {
            "kpi_label": "KPI #3",
            "header": "Response Rate - Calls",
            "rows": [
                ("Total Responses", lambda m: satisfaction["call_months"][m]["responses"], satisfaction["call_totals"]["responses"]),
                ("Total Complaints", lambda m: satisfaction["call_months"][m]["total"], satisfaction["call_totals"]["total"]),
                ("Result (%)", lambda m: satisfaction["call_months"][m]["rate"], satisfaction["call_totals"]["rate"], True),
            ],
        },
        {
            "kpi_label": "KPI #3",
            "header": "Response Rate - Survey",
            "rows": [
                ("Total Responses", lambda m: satisfaction["survey_months"][m]["responses"], satisfaction["survey_totals"]["responses"]),
                ("Total Complaints", lambda m: satisfaction["survey_months"][m]["total"], satisfaction["survey_totals"]["total"]),
                ("Result (%)", lambda m: satisfaction["survey_months"][m]["rate"], satisfaction["survey_totals"]["rate"], True),
            ],
        },
        {
            "kpi_label": "KPI #3",
            "header": "MOH KPI",
            "rows": [
                ("Complaints which received a (satisfied) scoring on its resolution", lambda m: moh_kpi["moh"]["months"][m]["satisfied_scoring"], moh_kpi["moh"]["totals"]["satisfied_scoring"]),
                ("Total number of complaints received", lambda m: moh_kpi["moh"]["months"][m]["total"], moh_kpi["moh"]["totals"]["total"]),
                ("Result (%)", lambda m: moh_kpi["moh"]["months"][m]["rate"], moh_kpi["moh"]["totals"]["rate"], True),
            ],
        },
        {
            "kpi_label": "KPI #3",
            "header": "MOH KPI - Real Numbers",
            "rows": [
                ("Complaints which received a (satisfied) scoring on its resolution", lambda m: moh_kpi["real"]["months"][m]["satisfied_scoring"], moh_kpi["real"]["totals"]["satisfied_scoring"]),
                ("Total number of complaints received", lambda m: moh_kpi["real"]["months"][m]["total"], moh_kpi["real"]["totals"]["total"]),
                ("Result (%)", lambda m: moh_kpi["real"]["months"][m]["rate"], moh_kpi["real"]["totals"]["rate"], True),
            ],
        },
        {
            "kpi_label": "KPI #4",
            "header": "Numerator/Denominator",
            "rows": [
                ("Total Responses Within 48 Hours", lambda m: kpi["months"][m]["resolved_48h"], kpi["totals"]["resolved_48h"]),
                ("Total Number of Complaints", lambda m: kpi["months"][m]["total"], kpi["totals"]["total"]),
                ("Result (%)", lambda m: kpi["months"][m]["resolved_48h_rate"], kpi["totals"]["resolved_48h_rate"], True),
            ],
        },
    ]

    ws = wb.create_sheet("1. KPI")
    row = 1

    for block in blocks:
        _style_header(ws, row, 1, block["header"])
        for i, ml in enumerate(months):
            _style_header(ws, row, 2 + i, ml)
        _style_header(ws, row, total_col, "Total")
        ws.cell(row=row, column=total_col + 2, value=block["kpi_label"]).font = BOLD_FONT
        ws.merge_cells(start_row=row, start_column=total_col + 2, end_row=row + 2, end_column=total_col + 2)

        for row_data in block["rows"]:
            row += 1
            is_pct = len(row_data) > 3 and row_data[3]
            _kpi_row(ws, row, row_data[0], row_data[1], row_data[2], is_pct)

        row += 2

    for c in range(1, total_col + 3):
        ws.column_dimensions[get_column_letter(c)].width = 16


def _write_source_table_sheet(wb, service):
    source = service.get_source_breakdown()
    source_totals = service.get_source_totals()
    location = service.get_location_breakdown()
    dept_type = service.get_dept_type_breakdown()
    dept_type_monthly = service.get_dept_type_monthly_table()
    monthly_summary = service.get_monthly_summary()
    location_ratios = service.get_location_ratios()
    quarterly_volumes = service.get_quarterly_volumes()
    active_months = service.active_months
    months = [calendar.month_abbr[m].upper() for m in active_months]

    ws = wb.create_sheet("2. 1st Table")

    def _month_col(idx):
        return 3 * idx + 5

    def _write_month_header(ws, row):
        _style_header(ws, row, 1, "%")
        _style_header(ws, row, 2, "Number")
        for i, m in enumerate(active_months):
            c = _month_col(i)
            _style_header(ws, row, c, months[i])

    def _write_subrow(ws, row, label, annual_total, get_monthly_count, get_monthly_pct):
        _style_data(ws, row, 4, annual_total)
        for i, m in enumerate(active_months):
            c = _month_col(i)
            _style_data(ws, row, c, label)
            cnt = get_monthly_count(m)
            if cnt:
                _style_data(ws, row, c + 1, cnt)
                pct = get_monthly_pct(m)
                if pct:
                    _style_data(ws, row, c + 2, pct, PCT_FMT)

    def _write_toprow(ws, row, pct, count, label, sub_label, sub_annual, get_sub_count, get_sub_pct):
        _style_data(ws, row, 1, pct, PCT_FMT)
        _style_data(ws, row, 2, count)
        _style_data(ws, row, 3, label)
        _write_subrow(ws, row, sub_label, sub_annual, get_sub_count, get_sub_pct)

    def _write_total_row(ws, row, total_all, monthly_totals):
        _style_data(ws, row, 1, "%")
        _style_data(ws, row, 2, "Number")
        _style_bold(ws, row, 4, total_all)
        for i, m in enumerate(active_months):
            c = _month_col(i)
            _style_data(ws, row, c, "Total")
            _style_data(ws, row, c + 1, monthly_totals[m])
            _style_data(ws, row, c + 2, 1, PCT_FMT)

    row = 1
    _write_month_header(ws, row)

    total_all = sum(source[m]["total"] for m in active_months)
    ext_total = sum(source[m]["external"] for m in active_months)
    int_total = sum(source[m]["internal"] for m in active_months)

    row = 2
    _style_data(ws, row, 1, round(ext_total / total_all, 3) if total_all else 0, PCT_FMT)
    _style_data(ws, row, 2, ext_total)
    _style_data(ws, row, 3, "External")

    row = 3
    moh_total = sum(source[m]["moh"] for m in active_months)
    _write_subrow(ws, row, "MOH", moh_total,
        lambda m: source[m]["moh"],
        lambda m: round(source[m]["moh"] / source[m]["total"], 3) if source[m]["total"] else 0)

    row = 4
    chi_total = sum(source[m]["chi"] for m in active_months)
    _write_subrow(ws, row, "CHI", chi_total,
        lambda m: source[m]["chi"],
        lambda m: round(source[m]["chi"] / source[m]["total"], 3) if source[m]["total"] else 0)

    row = 5
    pat_total = sum(source[m]["patients"] for m in active_months)
    _write_toprow(ws, row,
        round(int_total / total_all, 3) if total_all else 0, int_total, "Internal",
        "Patients", pat_total,
        lambda m: source[m]["patients"],
        lambda m: round(source[m]["patients"] / source[m]["total"], 3) if source[m]["total"] else 0)

    row = 6
    rel_total = sum(source[m]["relatives"] for m in active_months)
    _write_subrow(ws, row, "Patient's relatives", rel_total,
        lambda m: source[m]["relatives"],
        lambda m: round(source[m]["relatives"] / source[m]["total"], 3) if source[m]["total"] else 0)

    row = 7
    _write_total_row(ws, row, total_all, {m: source[m]["total"] for m in active_months})

    row = 9
    for label, key in [("In-Patient", "ip"), ("Out-Patient", "op"), ("ER", "er")]:
        total_v = sum(location[m][key] for m in active_months)
        _style_data(ws, row, 1, round(total_v / total_all, 3) if total_all else 0, PCT_FMT)
        _style_data(ws, row, 2, total_v)
        _style_data(ws, row, 3, label)
        _style_data(ws, row, 4, total_v)
        for i, m in enumerate(active_months):
            c = _month_col(i)
            _style_data(ws, row, c, label)
            cnt = location[m][key]
            if cnt:
                _style_data(ws, row, c + 1, cnt)
                _style_data(ws, row, c + 2, round(cnt / source[m]["total"], 3) if source[m]["total"] else 0, PCT_FMT)
        row += 1

    _write_total_row(ws, row, total_all, {m: source[m]["total"] for m in active_months})

    row += 2
    for label, key in [("Medical", "medical"), ("Administrative", "administrative"), ("Nursing", "nursing"), ("Support Services", "support")]:
        total_v = sum(dept_type[m][key] for m in active_months)
        _style_data(ws, row, 1, round(total_v / total_all, 3) if total_all else 0, PCT_FMT)
        _style_data(ws, row, 2, total_v)
        _style_data(ws, row, 3, label)
        _style_data(ws, row, 4, total_v)
        for i, m in enumerate(active_months):
            c = _month_col(i)
            _style_data(ws, row, c, label)
            cnt = dept_type[m][key]
            if cnt:
                _style_data(ws, row, c + 1, cnt)
                _style_data(ws, row, c + 2, round(cnt / dept_type[m]["total"], 3) if dept_type[m]["total"] else 0, PCT_FMT)
        row += 1

    _write_total_row(ws, row, total_all, {m: source[m]["total"] for m in active_months})

    row += 2
    summary_headers = ["Month", "MOH Complaints", "CHI", "Internal", "Total Complaints", "MOH Percentage", "CCHI Percentage"]
    for i, h in enumerate(summary_headers):
        _style_header(ws, row, 5 + i, h)

    for ms in monthly_summary:
        row += 1
        _style_data(ws, row, 5, ms["month"])
        _style_data(ws, row, 6, ms["moh"])
        _style_data(ws, row, 7, ms["chi"])
        _style_data(ws, row, 8, ms["internal"])
        _style_data(ws, row, 9, ms["total"])
        _style_data(ws, row, 10, ms["moh_pct"], PCT_FMT)
        _style_data(ws, row, 11, ms["chi_pct"], PCT_FMT)

    row += 2
    source_total_items = [
        ("Internal Complaints", source_totals["internal"]["count"], "% Internal", source_totals["internal"]["pct"]),
        ("External Complaints", source_totals["external"]["count"], "% External", source_totals["external"]["pct"]),
    ]
    for label, count, pct_label, pct in source_total_items:
        _style_bold(ws, row, 6, label)
        _style_data(ws, row, 7, count)
        _style_bold(ws, row, 9, pct_label)
        _style_data(ws, row, 10, pct, PCT_FMT)
        row += 1

    row += 1
    for area, title, comp_col, pat_col in [
        ("ip", "In-Patient Complaints vs Patients", "In-Patient Complaints", "Total In-Patient "),
        ("op", "Out-Patient Complaints vs Patients", "Out-Patient Complaint", "Total Out-Patient"),
        ("er", "ER Complaints vs Patients", "ER Complaints", "Total ER Patients"),
    ]:
        headers = ["Month", comp_col, pat_col, "Persentage"]
        for i, h in enumerate(headers):
            _style_header(ws, row, 5 + i, h)
        for i, m in enumerate(active_months):
            row += 1
            d = location_ratios["months"][m]
            _style_data(ws, row, 5, months[i])
            _style_data(ws, row, 6, d[f"{area}_complaints"])
            _style_data(ws, row, 7, d[f"{area}_patients"])
            _style_data(ws, row, 8, d[f"{area}_ratio"] if d[f"{area}_patients"] > 0 else "-", PCT_FMT)
        row += 1
        t = location_ratios["totals"][area]
        _style_bold(ws, row, 5, "TOTAL")
        _style_bold(ws, row, 6, t["complaints"])
        _style_bold(ws, row, 7, t["patients"])
        _style_bold(ws, row, 8, t["ratio"] if t["patients"] > 0 else "-", PCT_FMT)
        row += 1

    row += 1
    summary_ratio_data = [
        ("In-Patient Complaints", location_ratios["totals"]["ip"]["complaints"],
         "Total In-Patient ", location_ratios["totals"]["ip"]["patients"],
         "Ratio", location_ratios["totals"]["ip"]["ratio"]),
        ("Out-Patient Complaint", location_ratios["totals"]["op"]["complaints"],
         "Total Out-Patient", location_ratios["totals"]["op"]["patients"],
         "Ratio", location_ratios["totals"]["op"]["ratio"]),
        ("ER Complaints", location_ratios["totals"]["er"]["complaints"],
         "Total ER Patients", location_ratios["totals"]["er"]["patients"],
         "Ratio", location_ratios["totals"]["er"]["ratio"]),
    ]
    for comp_label, comp_count, pat_label, pat_count, ratio_label, ratio_val in summary_ratio_data:
        _style_bold(ws, row, 10, comp_label)
        _style_data(ws, row, 11, comp_count)
        _style_bold(ws, row, 12, ratio_val, PCT_FMT)
        row += 1

    row += 1
    for q_num in ["1", "2", "3", "4"]:
        q_data = quarterly_volumes.get(q_num, {})
        q_months = q_data.get("months", {})
        _style_header(ws, row, 10, "Area/Unit")
        for i, m_num in enumerate(sorted(q_months.keys())):
            _style_header(ws, row, 11 + i, months[m_num - 1])
        _style_header(ws, row, 14, "Total")

        row += 1
        for area_label, area_key in [("OPD", "OPD"), ("ER", "ER"), ("IP", "IP")]:
            _style_data(ws, row, 10, area_label)
            q_total = 0
            for i, m_num in enumerate(sorted(q_months.keys())):
                val = q_months[m_num].get(area_key, 0)
                _style_data(ws, row, 11 + i, val)
                q_total += val
            _style_data(ws, row, 14, q_total)
            row += 1

    row += 1
    dept_headers = ["Month", "Medical", "Administrative", "Nursing", "Support Services", "Total Complaints"]
    for i, h in enumerate(dept_headers):
        _style_header(ws, row, 5 + i, h)

    for mr in dept_type_monthly["months"]:
        row += 1
        _style_data(ws, row, 5, mr["month"])
        _style_data(ws, row, 6, mr["medical"])
        _style_data(ws, row, 7, mr["administrative"])
        _style_data(ws, row, 8, mr["nursing"])
        _style_data(ws, row, 9, mr["support"])
        _style_data(ws, row, 10, mr["total"])

    row += 1
    _style_bold(ws, row, 5, "TOTAL")
    _style_bold(ws, row, 6, dept_type_monthly["totals"]["medical"])
    _style_bold(ws, row, 7, dept_type_monthly["totals"]["administrative"])
    _style_bold(ws, row, 8, dept_type_monthly["totals"]["nursing"])
    _style_bold(ws, row, 9, dept_type_monthly["totals"]["support"])
    _style_bold(ws, row, 10, dept_type_monthly["totals"]["total"])

    row += 1
    _style_bold(ws, row, 5, "% From total")
    _style_bold(ws, row, 6, dept_type_monthly["percentages"]["medical"], PCT_FMT)
    _style_bold(ws, row, 7, dept_type_monthly["percentages"]["administrative"], PCT_FMT)
    _style_bold(ws, row, 8, dept_type_monthly["percentages"]["nursing"], PCT_FMT)
    _style_bold(ws, row, 9, dept_type_monthly["percentages"]["support"], PCT_FMT)
    _style_bold(ws, row, 10, dept_type_monthly["percentages"]["total"], PCT_FMT)

    row += 2
    for i, h in enumerate(["Medical", "Administrative", "Nursing", "Support Services", "Total Complaints"]):
        _style_header(ws, row, 5 + i, h)
    row += 1
    _style_data(ws, row, 5, "Persentage")
    _style_data(ws, row, 6, dept_type_monthly["percentages"]["medical"], PCT_FMT)
    _style_data(ws, row, 7, dept_type_monthly["percentages"]["administrative"], PCT_FMT)
    _style_data(ws, row, 8, dept_type_monthly["percentages"]["nursing"], PCT_FMT)
    _style_data(ws, row, 9, dept_type_monthly["percentages"]["support"], PCT_FMT)
    _style_data(ws, row, 10, dept_type_monthly["percentages"]["total"], PCT_FMT)
    row += 1
    _style_bold(ws, row, 5, "TOTAL")
    _style_bold(ws, row, 6, dept_type_monthly["totals"]["medical"])
    _style_bold(ws, row, 7, dept_type_monthly["totals"]["administrative"])
    _style_bold(ws, row, 8, dept_type_monthly["totals"]["nursing"])
    _style_bold(ws, row, 9, dept_type_monthly["totals"]["support"])
    _style_bold(ws, row, 10, dept_type_monthly["totals"]["total"])

    for c in range(1, 42):
        ws.column_dimensions[get_column_letter(c)].width = 14
    ws.column_dimensions["C"].width = 22


def _write_escalated_sheet(wb, service):
    escalated = service.get_escalated_breakdown()
    by_cat = escalated["by_category"]
    by_source = escalated.get("by_source", {})

    ws = wb.create_sheet("3. Escalated Complaints")

    categories = [
        ("Medical", "medical"),
        ("Administrative", "administrative"),
        ("Nursing", "nursing"),
        ("Support Services", "support_services"),
    ]

    cat_headers = []
    for cat_label, cat_key in categories:
        cat_headers.append((cat_label, "Sub-department"))
        cat_headers.append((cat_label, "Escalated"))

    num_cols = len(cat_headers)
    for i in range(num_cols):
        _style_header(ws, 1, i + 1, cat_headers[i][1])
    for i in range(0, num_cols, 2):
        ws.cell(row=1, column=i + 1).value = cat_headers[i][0]
        ws.merge_cells(start_row=1, start_column=i + 1, end_row=1, end_column=i + 2)
        ws.cell(row=1, column=i + 1).font = HEADER_FONT
        ws.cell(row=1, column=i + 1).fill = BLUE_FILL
        ws.cell(row=1, column=i + 1).alignment = CENTER

    _style_header(ws, 2, 1, "Sub-department")
    _style_header(ws, 2, 2, "Escalated")
    for i in range(2, num_cols, 2):
        _style_header(ws, 2, i + 1, "Sub-department")
        _style_header(ws, 2, i + 2, "Escalated")

    max_rows = max(
        len(by_cat.get(cat_key, {})) for _, cat_key in categories
    )

    cat_totals = {}
    for cat_label, cat_key in categories:
        depts = by_cat.get(cat_key, {})
        cat_totals[cat_key] = {
            "total_escalated": sum(depts.values()),
            "total_complaints": 0,
        }
        sorted_depts = sorted(depts.items(), key=lambda x: -x[1])
        col_start = categories.index((cat_label, cat_key)) * 2 + 1
        for r, (dept_name, count) in enumerate(sorted_depts):
            _style_data(ws, 3 + r, col_start, dept_name)
            _style_data(ws, 3 + r, col_start + 1, count)
        total_row = 3 + max_rows
        _style_bold(ws, total_row, col_start, "Total")
        _style_bold(ws, total_row, col_start + 1, sum(depts.values()))

        total_complaints_row = total_row + 1
        _style_bold(ws, total_complaints_row, col_start, "Total Complaints")
        per_dept = service.get_per_department_breakdown()
        dept_names = [d["name"] for d in per_dept["categories"].get(cat_key, [])]
        tc = sum(d["total"] for d in per_dept["categories"].get(cat_key, []))
        _style_bold(ws, total_complaints_row, col_start + 1, tc)

        pct_row = total_complaints_row + 1
        esc_count = sum(depts.values())
        _style_bold(ws, pct_row, col_start, "% Escalated Complaints")
        _style_bold(ws, pct_row, col_start + 1, round(esc_count / tc, 3) if tc > 0 else 0, PCT_FMT)

    summary_row = 3 + max_rows + 4
    ws.cell(row=summary_row, column=1, value="Total number of Escalated Complaints").font = BOLD_FONT
    row = summary_row + 1
    for label, key in [("Internal Complaints", "internal"), ("MOH", "moh"), ("CHI", "chi")]:
        _style_bold(ws, row, 1, label)
        _style_data(ws, row, 2, by_source.get(key, 0))
        row += 1
    _style_bold(ws, row, 1, "Total")
    _style_data(ws, row, 2, sum(by_source.values()))

    for c in range(1, num_cols + 1):
        ws.column_dimensions[get_column_letter(c)].width = 30 if c % 2 == 1 else 12


def _write_per_department_sheet(wb, service):
    per_dept = service.get_per_department_breakdown()
    categories = per_dept["categories"]
    source_totals = per_dept["source_totals"]

    ws = wb.create_sheet("4. Each dep. complaints")

    cat_configs = [
        ("Medical", "medical", 2),
        ("Administrative", "administrative", 12),
        ("Nursing", "nursing", 20),
        ("Support Services", "support_services", 28),
    ]

    for cat_label, cat_key, col_start in cat_configs:
        _style_header(ws, 1, col_start, cat_label)
        ws.merge_cells(start_row=1, start_column=col_start, end_row=1, end_column=col_start + 6)

        sub_headers = ["Sub-dept", "MOH", "CHI", "Internal", "Total", "Escalated", "Response Rate (Days)"]
        for i, h in enumerate(sub_headers):
            _style_header(ws, 2, col_start + i, h)

        depts = categories.get(cat_key, [])
        for r, d in enumerate(depts):
            row = 3 + r
            _style_data(ws, row, col_start, d["name"])
            _style_data(ws, row, col_start + 1, d["moh"])
            _style_data(ws, row, col_start + 2, d["chi"])
            _style_data(ws, row, col_start + 3, d["internal"])
            _style_data(ws, row, col_start + 4, d["total"])
            _style_data(ws, row, col_start + 5, d["escalated"])
            _style_data(ws, row, col_start + 6, d["avg_response_days"], NUM_FMT)

        total_row = 3 + len(depts)
        _style_bold(ws, total_row, col_start, "Total")
        _style_bold(ws, total_row, col_start + 1, sum(d["moh"] for d in depts))
        _style_bold(ws, total_row, col_start + 2, sum(d["chi"] for d in depts))
        _style_bold(ws, total_row, col_start + 3, sum(d["internal"] for d in depts))
        _style_bold(ws, total_row, col_start + 4, sum(d["total"] for d in depts))
        _style_bold(ws, total_row, col_start + 5, sum(d["escalated"] for d in depts))

    summary_row = 3 + max(len(categories.get(ck, [])) for _, ck, _ in cat_configs) + 3

    source_items = [
        ("MOH", source_totals["moh"]),
        ("CHI", source_totals["chi"]),
        ("Internal", source_totals["internal"]),
        ("Total", source_totals["total"]),
    ]
    for label, val in source_items:
        _style_bold(ws, summary_row, 2, label)
        _style_data(ws, summary_row, 3, val)
        summary_row += 1

    avg_row = summary_row + 1
    _style_bold(ws, avg_row, 2, "Average Response Rate")
    avg_row += 1
    avg_resp = per_dept.get("avg_response_days", {})
    for cat_label, cat_key, _ in cat_configs:
        _style_data(ws, avg_row, 2, cat_label)
        _style_data(ws, avg_row, 3, avg_resp.get(cat_key, 0), NUM_FMT)
        avg_row += 1

    for c in range(1, 40):
        ws.column_dimensions[get_column_letter(c)].width = 12
    for _, _, cs in cat_configs:
        ws.column_dimensions[get_column_letter(cs)].width = 30


def _write_response_rate_sheet(wb, title, rate_data):
    ws = wb.create_sheet(title)
    _style_header(ws, 1, 1, "Timeline")
    _style_header(ws, 1, 2, "Count")
    _style_header(ws, 1, 3, "Rate")

    buckets = ["24h", "48h", "72h", "72h+"]
    for i, b in enumerate(buckets):
        row = 2 + i
        _style_data(ws, row, 1, b)
        _style_data(ws, row, 2, rate_data["counts"].get(b, 0))
        _style_data(ws, row, 3, rate_data["rates"].get(b, 0), PCT_FMT)

    row = 6
    _style_bold(ws, row, 1, "Total")
    _style_data(ws, row, 2, rate_data["total"])

    individual = rate_data.get("individual", [])
    if individual:
        row += 2
        _style_header(ws, row, 1, "Reference")
        _style_header(ws, row, 2, "Department")
        _style_header(ws, row, 3, "Hours")
        _style_header(ws, row, 4, "Bucket")
        _style_header(ws, row, 5, "Status")
        for i, item in enumerate(individual):
            r = row + 1 + i
            _style_data(ws, r, 1, item["ref"])
            _style_data(ws, r, 2, item["dept"])
            _style_data(ws, r, 3, item["hours"], NUM_FMT)
            _style_data(ws, r, 4, item["bucket"])
            _style_data(ws, r, 5, item["status"])

    chart = PieChart()
    chart.title = f"{title}"
    data_ref = Reference(ws, min_col=2, min_row=1, max_row=5)
    cats_ref = Reference(ws, min_col=1, min_row=2, max_row=5)
    chart.add_data(data_ref, titles_from_data=True)
    chart.set_categories(cats_ref)
    ws.add_chart(chart, "G2")

    ws.column_dimensions["A"].width = 18
    ws.column_dimensions["B"].width = 30
    ws.column_dimensions["C"].width = 12
    ws.column_dimensions["D"].width = 14
    ws.column_dimensions["E"].width = 12


def _write_per_dept_response_rate_sheets(wb, service):
    dept_times = service.get_per_dept_response_times()

    sheet_configs = [
        ("8.1 Response Rate Medical", ["medical"]),
        ("8.2 Response Rate Administrative", ["administrative", "admin"]),
        ("8.3 RR Nursing&Support", ["nursing", "support_services"]),
    ]

    for sheet_title, domain_types in sheet_configs:
        ws = wb.create_sheet(sheet_title)

        all_depts = {}
        for dt in domain_types:
            all_depts.update(dept_times.get(dt, {}))

        if not all_depts:
            continue

        dept_names = sorted(all_depts.keys())
        col = 2
        for dept_name in dept_names:
            cell = ws.cell(row=1, column=col, value=dept_name)
            cell.font = HEADER_FONT
            cell.fill = BLUE_FILL
            cell.alignment = CENTER
            cell.border = BORDER_ALL
            ws.merge_cells(start_row=1, start_column=col, end_row=1, end_column=col)

            cell2 = ws.cell(row=2, column=col)
            cell2.value = "Time between processing and sending"
            cell2.font = Font(name="Calibri", size=9, italic=True)
            cell2.alignment = CENTER
            cell2.border = BORDER_ALL

            times = all_depts[dept_name]
            for i, t in enumerate(times):
                r = 3 + i
                if t.get("status") == "Escalated":
                    _style_data(ws, r, col, "Escalated")
                elif t.get("status") == "Closed":
                    _style_data(ws, r, col, "Closed")
                else:
                    hours = t["hours"]
                    days = int(hours // 24)
                    remaining_hours = int(hours % 24)
                    td_str = f"{days}d {remaining_hours}h" if days > 0 else f"{int(hours)}h"
                    _style_data(ws, r, col, td_str)

            col += 1

        ws.column_dimensions["A"].width = 5
        for c in range(2, col):
            ws.column_dimensions[get_column_letter(c)].width = 22


def generate_complaint_quarterly_excel(service):
    wb = Workbook()
    wb.remove(wb.active)

    _write_all_quarters_sheet(wb, service)
    _write_kpi_sheet(wb, service)
    _write_source_table_sheet(wb, service)
    _write_escalated_sheet(wb, service)
    _write_per_department_sheet(wb, service)

    response_rates = service.get_response_rates()
    _write_response_rate_sheet(wb, "5. Internal Response Rate", response_rates["internal"])
    _write_response_rate_sheet(wb, "6. MOH Response Rate", response_rates["moh"])
    _write_response_rate_sheet(wb, "7. CHI Response Rate", response_rates["chi"])

    _write_per_dept_response_rate_sheets(wb, service)

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