"""打印用 HTML（复刻旧 .aspx / .ascx）。所有动态值必须经 esc() 转义。"""
import datetime as dt

from flyway.models import PackingSlip, Transfer
from flyway.printing.fill import NA, esc, nz, time_text

PAGE_CSS = """<style>
table caption{font-size:16px;font-weight:bold}
.table{border:1px solid #000;border-spacing:0;empty-cells:show;border-collapse:collapse}
.table td,.table th{padding:5px;border:1px solid #000}
.datagrid table{border-collapse:collapse;text-align:left;width:100%}
.datagrid{font:normal 12px/150% Arial,Helvetica,sans-serif;background:#fff;border:1px solid #006699}
.datagrid table td,.datagrid table th{padding:3px 10px}
.datagrid table thead th{background:#006699;color:#fff;font-size:15px;font-weight:bold;border-left:1px solid #0070A8}
.datagrid table thead th:first-child{border:none}
.datagrid table tr{border-bottom:1px dotted #E1EEF4}
.datagrid table tbody td{color:#00557F;border-left:1px solid #E1EEF4;font-size:12px}
.datagrid table tbody .alt td{background:#E1EEf4}
.datagrid table tbody td:first-child{border-left:none}
.datagrid table tbody tr:last-child td{border-bottom:none}
.datagrid table tfoot td{font-size:12px;padding:0}
.datagrid table tfoot td div{background:#E1EEf4;border-top:1px solid #006699;padding:2px}
.noprint{margin-bottom:12px}
@media print{.noprint{display:none}}
</style>"""


def page(title: str, body: str, extra_head: str = "") -> str:
    return (f"<!doctype html><html><head><meta charset='utf-8'><title>{esc(title)}</title>{PAGE_CSS}{extra_head}"
            f"</head><body>{body}</body></html>")


def ddmmyyyy(d: dt.date | None) -> str:
    return d.strftime("%d/%m/%Y") if d else ""


def _items(t: Transfer):
    return sorted(t.items, key=lambda i: i.batch.product.title.casefold())


def attachment_block(t: Transfer) -> str:
    """Check sheet PDF 第二页的产品清单（Blocks/Attachment.ascx）。"""
    kind = "Load-out" if t.is_load_out else "Load-in"
    rows = "".join(
        f"<tr><td>{esc(i.batch.product.title)}</td><td>{i.quantity}ctns ({i.unit})</td>"
        f"<td>{esc(i.batch.number)}</td><td>{esc(ddmmyyyy(i.batch.used_by_date) or NA)}</td></tr>"
        for i in _items(t))
    return (f"<table width='100%' style='border-spacing:0;border:0 none'><tbody><tr>"
            f"<td style='text-align:center;font-size:16px;font-weight:bold;padding-bottom:15px'>{kind} Attachment</td>"
            f"</tr><tr><td><table width='100%' border='1' cellpadding='5'>"
            f"<thead><tr><th>Product name</th><th>Quantity</th><th>Batch number</th><th>Use by date</th></tr></thead><tbody>{rows}</tbody>"
            f"</table></td></tr></tbody></table>")


_PRINT_HEAD = """<table align="center" width="600" class="table" style="font-size:12px;margin-bottom:20px">
<tr><td>ssue No: 2</td><td style="text-align:center"><h1>Flyway Express Limited<br />2142/01 – ULI S2142</h1></td>
<td>SP-006 Appendix-2</td></tr>
<tr><td>Issue Date: December 2012</td><td><h1>LOAD IN - LOAD OUT</h1></td><td>1 of 1</td></tr></table>"""


def _toolbar() -> str:
    return ""


_LABELLING_DAIRY = """<table align="center" width="600" class="table" style="font-size:12px"><tr><td><b>Labelling Dairy:</b><ul>
<li>Labels on outer packaging must display the product description</li>
<li>Net contents may be on the label or with accompanying documentation</li>
<li>Labels on the outer packaging must have information to enable traceability: either unique location identifier or name and address, and either lot identification or the date of manufacture or packaging</li>
</ul></td></tr></table>"""

def attachment_page(t: Transfer) -> str:
    """/LoadIn/Attachment、/LoadOut/Attachment。"""
    kind = "Load-out" if t.is_load_out else "Load-in"
    rows = "".join(
        f"<tr><td>{esc(i.batch.product.title)}</td><td>{i.quantity}</td><td>{esc(i.batch.number)}</td>"
        f"<td>{esc(ddmmyyyy(i.batch.used_by_date) or NA)}</td></tr>" for i in t.items)
    body = (f"{_toolbar()}{_PRINT_HEAD}<table width='700' align='center' style='border-spacing:0;border:0 none'>"
            f"<caption>{kind} Attachment</caption><tbody><tr><td><table width='100%' class='table'>"
            f"<thead><tr><th>Product name</th><th>Quantity</th><th>Batch number</th><th>Use by date</th></tr></thead><tbody>{rows}</tbody>"
            f"</table></td></tr></tbody></table>")
    return page(f"{kind} Attachment", body + _LABELLING_DAIRY)


def table_page(t: Transfer) -> str:
    """/LoadIn/Table、/LoadOut/Table：LOAD IN - LOAD OUT 登记表。"""
    out = t.is_load_out
    kind = "Load-out" if out else "Load-in"
    when = f"<td>{esc(nz(t.date).strftime('%d/%m/%Y'))}</td>"
    tm = f"<td>{esc(time_text(t.date))}</td>"
    if out:
        codes = dict.fromkeys(i.main_item.transfer.code for i in t.items if i.main_item)
        place = f"<th>Destination</th><td>{esc(t.to_location)} {esc(t.to_rmp)}</td>"
        dates = f"<tr><th>Dispatch Date</th>{when}<th>Dispatch Time</th>{tm}</tr>"
        ref = f"<tr><th>Shipment Reference Number</th><td colspan='10'>{' '.join(f'<span>{esc(c)}</span>' for c in codes)}</td></tr>"
        head_rows = dates + ref
    else:
        # 保留旧 LoadIn/Table.aspx 的显示字段，满足旧单据内容兼容。
        place = f"<th>premises of Origin</th><td>{esc(t.to_location)} {esc(t.to_rmp)}</td>"
        ref = f"<tr><th>Shipment Reference Number</th><td colspan='10'><span>{esc(t.code)}</span></td></tr>"
        head_rows = ref + f"<tr><th>Receive Date</th>{when}<th>Receive Time</th>{tm}</tr>"
    see = "<td colspan='10'>SEE ATTACHMENT</td>"
    body = f"""{_toolbar()}{_PRINT_HEAD}
<table width="700" align="center" style="border-spacing:0;border:0 none"><caption>{kind} Check Sheet</caption><tbody>
<tr><td width="25"></td><td><table width="100%" class="table">
<tr><th>Client</th><td>{esc(t.client.name)}</td>{place}</tr>{head_rows}
<tr><th>Product Description</th>{see}</tr><tr><th>Quantity &amp; Packages</th>{see}</tr>
<tr><th>Date Code / Batch Code / Marks</th>{see}</tr>
<tr><th>Transport Company</th><td colspan="10">{esc(t.transport_company)} {esc(t.vehicle_registration)}</td></tr>
<tr><th>Condition of vehicle?</th><td>{esc(t.condition_of_vehicle)}</td><th>Non-conforming product?</th>
<td>{'Yes' if t.non_conforming_product else 'No'}</td></tr>
<tr><th>Container Number</th><td>{esc(t.container_number or NA)}</td><th>Seal Number</th><td>{esc(t.seal_number or NA)}</td></tr>
<tr><th>Can Number</th><td>{esc(t.can_number or NA)}</td><th>AWB Number</th><td>{esc(t.awb_number or NA)}</td></tr>
</table></td><td width="25"></td></tr>
<tr><td colspan="2"><table width="100%" class="table"><tr><td rowspan="2" width="25"><div>Dairy</div></td>
<td rowspan="2">Labelling Checked<br /><b>Yes / No</b></td><td>Product Name</td><td>Net Contents</td>
<td>ULI or Name and address of manufacturer</td><td>Lot ID</td><td>Date of manufacture or packing</td></tr>
<tr><td><br /></td><td><br /></td><td><br /></td><td><br /></td><td><br /></td></tr></table></td><td></td></tr>
<tr><td></td><td><table width="100%" class="table"><tr><td><b>Consignment matches documentation</b> (e.g. Packing slip)</td>
<td><b>Yes / No</b></td></tr><tr><td colspan="2"><b>Notes:</b><br /><br /><br /><br /><br /></td></tr></table>
<table width="100%" class="table"><tr><th>Dispatcher Signature</th><td></td><th>Supervisor Signature</th><td></td></tr></table>
</td><td></td></tr></tbody></table>
{_LABELLING_DAIRY}"""
    return page(f"{kind} Check Sheet", body)


def slip_product_list(s: PackingSlip) -> str:
    """装箱单 {{ProductList}}（Blocks/ProductList.ascx），含旧的按行数分页（每页约 23 行）。"""
    items = [i for t in s.transfers if t.is_load_out and not t.is_draft for i in t.items]
    items.sort(key=lambda i: (i.batch.product.title.casefold(), i.transfer.code.casefold(), i.batch.number.casefold()))
    groups: dict = {}
    for i in items:
        groups.setdefault(i.batch_id, []).append(i)
    head = ("<table width='100%' style='margin-top:150px'><thead><tr>"
            "<th style='width:40%'>DESCRIPTION</th><th style='width:15%'>QUANTITY</th>"
            "<th style='width:25%'>Batch number</th><th style='width:20%'>Use by date</th>"
            "</tr></thead><tbody>")
    td = "border-bottom:1px solid #000;font-size:14px;overflow-wrap:anywhere;"
    out, total, count = [head], 0, 0
    for group in groups.values():
        b = group[0].batch
        by_unit: dict[int, int] = {}
        for i in group:
            by_unit[i.unit] = by_unit.get(i.unit, 0) + i.quantity
        qty = ", ".join(f"{q} ({u}pcs)" for u, q in by_unit.items())
        ubd = ddmmyyyy(b.used_by_date) or NA
        total += sum(i.quantity for i in group)
        rows = max((len(b.product.title) + 25) // 26, (len(qty) + 9) // 10, (len(b.number) + 18) // 19)
        count += rows
        if count > 23:
            count = rows
            out.append("</tbody></table>" + head)
        out.append(f"<tr><td style='{td}'>{esc(b.product.title)}</td><td style='{td}'>{esc(qty)}</td>"
                   f"<td style='{td}'>{esc(b.number)}</td><td style='{td}'>{esc(ubd)}</td></tr>")
    out.append(f"<tr><td colspan='4' style='text-align:right;padding-top:10px'>Total {total} ctns.</td></tr></tbody></table>")
    return "".join(out)
