import io
import json

import xlsxwriter
from markupsafe import escape

from odoo import http
from odoo.http import content_disposition, request

# The Leave Balances "Grid" view is a pivoted employee x leave-type table
# built client-side (leave_balance_action.js's gridRows), not a flat list of
# hr.leave.allocation records -- core's generic /web/export/xlsx writes one
# row per record and can't reproduce the merged leave-type header groups, so
# it can't be reused here. Instead the already-computed grid (exactly what's
# on screen) is posted to these two routes, which lay it out as an .xlsx
# (via xlsxwriter, same library core's own export uses) or a .pdf (via
# wkhtmltopdf through ir.actions.report._run_wkhtmltopdf, with no report
# record/QWeb template needed since the grid is plain rows, not a res_model).

USED_COLOR = "#a33a49"
REMAINING_COLOR = "#206b45"


def _grid_payload(data):
    payload = json.loads(data)
    return payload.get("leave_types") or [], payload.get("rows") or [], payload.get("year") or ""


class XenoLeaveGridExport(http.Controller):

    @http.route("/xeno_leave/grid_export/xlsx", type="http", auth="user")
    def grid_export_xlsx(self, data):
        leave_types, rows, year = _grid_payload(data)

        output = io.BytesIO()
        workbook = xlsxwriter.Workbook(output, {"in_memory": True})
        sheet = workbook.add_worksheet("Leave Balances Grid")

        header_fmt = workbook.add_format({
            "bold": True, "bg_color": "#fafafa", "border": 1,
            "align": "center", "valign": "vcenter",
        })
        name_fmt = workbook.add_format({"bold": True, "border": 1})
        code_fmt = workbook.add_format({"border": 1, "font_color": "#6b6b6b"})
        plain_fmt = workbook.add_format({"border": 1, "align": "right"})
        used_fmt = workbook.add_format({"border": 1, "align": "right", "font_color": USED_COLOR})
        remaining_fmt = workbook.add_format({
            "border": 1, "align": "right", "font_color": REMAINING_COLOR, "bold": True,
        })

        sheet.merge_range(0, 0, 1, 0, "Employee", header_fmt)
        sheet.merge_range(0, 1, 1, 1, "Employee Code", header_fmt)
        col = 2
        for lt in leave_types:
            sheet.merge_range(0, col, 0, col + 2, lt.get("name", ""), header_fmt)
            sheet.write(1, col, "Allocated", header_fmt)
            sheet.write(1, col + 1, "Used", header_fmt)
            sheet.write(1, col + 2, "Remaining", header_fmt)
            col += 3
        sheet.set_column(0, 0, 24)
        sheet.set_column(1, 1, 14)
        if leave_types:
            sheet.set_column(2, col - 1, 11)

        r = 2
        for row in rows:
            sheet.write(r, 0, row.get("employeeName", ""), name_fmt)
            sheet.write(r, 1, row.get("employeeCode", ""), code_fmt)
            c = 2
            for cell in row.get("cells", []):
                sheet.write(r, c, cell.get("allocatedStr", ""), plain_fmt)
                sheet.write(r, c + 1, cell.get("usedStr", ""), used_fmt)
                sheet.write(r, c + 2, cell.get("remainingStr", ""), remaining_fmt)
                c += 3
            r += 1

        sheet.freeze_panes(2, 2)
        workbook.close()
        output.seek(0)

        return request.make_response(
            output.read(),
            headers=[
                ("Content-Type",
                 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
                ("Content-Disposition",
                 content_disposition(f"Leave_Balances_Grid_{year}.xlsx")),
            ],
        )

    @http.route("/xeno_leave/grid_export/pdf", type="http", auth="user")
    def grid_export_pdf(self, data):
        leave_types, rows, year = _grid_payload(data)
        html = self._build_html(leave_types, rows, year)

        pdf_content = request.env["ir.actions.report"].sudo()._run_wkhtmltopdf(
            [html], landscape=True)

        return request.make_response(
            pdf_content,
            headers=[
                ("Content-Type", "application/pdf"),
                ("Content-Disposition",
                 content_disposition(f"Leave_Balances_Grid_{year}.pdf")),
            ],
        )

    def _build_html(self, leave_types, rows, year):
        type_headers = "".join(
            f'<th colspan="3">{escape(lt.get("name", ""))}</th>' for lt in leave_types
        )
        sub_headers = "<th>Allocated</th><th>Used</th><th>Remaining</th>" * len(leave_types)

        body_rows = []
        for row in rows:
            cells = "".join(
                f'<td class="num">{escape(c.get("allocatedStr", ""))}</td>'
                f'<td class="num used">{escape(c.get("usedStr", ""))}</td>'
                f'<td class="num remaining">{escape(c.get("remainingStr", ""))}</td>'
                for c in row.get("cells", [])
            )
            body_rows.append(
                f'<tr><td class="name">{escape(row.get("employeeName", ""))}</td>'
                f'<td class="code">{escape(row.get("employeeCode", ""))}</td>{cells}</tr>'
            )

        return f"""<!DOCTYPE html><html><head><meta charset="utf-8"/><style>
            body {{ font-family: Arial, Helvetica, sans-serif; font-size: 11px; }}
            h2 {{ margin: 0 0 12px; color: #1a2b4a; }}
            table {{ border-collapse: collapse; width: 100%; }}
            th, td {{ border: 1px solid #ccc; padding: 4px 8px; }}
            th {{ background: #fafafa; text-align: center; }}
            td.name {{ font-weight: bold; }}
            td.code {{ color: #6b6b6b; }}
            td.num {{ text-align: right; }}
            td.used {{ color: {USED_COLOR}; }}
            td.remaining {{ color: {REMAINING_COLOR}; font-weight: bold; }}
        </style></head><body>
            <h2>Leave Balances Grid &mdash; {escape(str(year))}</h2>
            <table>
                <thead>
                    <tr><th rowspan="2">Employee</th><th rowspan="2">Employee Code</th>{type_headers}</tr>
                    <tr>{sub_headers}</tr>
                </thead>
                <tbody>{"".join(body_rows)}</tbody>
            </table>
        </body></html>"""
