"""旧模板兼容替换器与单据数据字典（旧 Template.GenerateContent / DataDictionaryExtensions）。"""
import datetime as dt
import html
import re

from flyway.domain.clock import NZ
from flyway.models import PackingSlip, Transfer

KEY = re.compile(r"\{\{(\w+)\}\}")
NA = "N/A"


def fill(template: str | None, data: dict[str, str]) -> str:
    """只替换 data 里有的 {{Key}}；未知占位符与其它花括号原样保留（旧引擎行为）。"""
    if not template:
        return ""
    return KEY.sub(lambda m: data.get(m.group(1), m.group(0)), template)


def esc(value) -> str:
    return html.escape("" if value is None else str(value))


def nz(value: dt.datetime) -> dt.datetime:
    return value.astimezone(NZ)


def date_text(value: dt.datetime) -> str:
    """d/M/yyyy（新西兰时间）。"""
    d = nz(value)
    return f"{d.day}/{d.month}/{d.year}"


def time_text(value: dt.datetime) -> str:
    """旧 ToShortTimeString（en 区域）：h:mm AM/PM。"""
    d = nz(value)
    return f"{d.hour % 12 or 12}:{d.minute:02d} {'AM' if d.hour < 12 else 'PM'}"


def _show(value) -> str:
    return value if value else NA


def transfer_data(t: Transfer) -> dict[str, str]:
    raw = {
        "ClientName": t.client.name, "FromLocation": t.from_location, "FromRmp": t.from_rmp,
        "ToLocation": t.to_location, "ToRmp": t.to_rmp, "Reference": t.code,
        "Date": date_text(t.date), "Time": time_text(t.date), "TransportCompany": t.transport_company,
        "VehicleRegistration": t.vehicle_registration, "ConditionOfVehicle": t.condition_of_vehicle,
        "NonConformingProduct": "Yes" if t.non_conforming_product else "No",
        # 旧代码只有以下字段空值显示 N/A
        "ContainerNumber": _show(t.container_number), "SealNumber": _show(t.seal_number),
        "CanNumber": _show(t.can_number), "AwbNumber": _show(t.awb_number),
        "EdIdentification": _show(t.ed_identification), "ExportTo": _show(t.export_to), "Notes": _show(t.notes),
    }
    return {k: esc(v) for k, v in raw.items()}


def slip_data(s: PackingSlip) -> dict[str, str]:
    raw = {"Reference": s.reference, "Date": date_text(s.date), "Time": time_text(s.date),
           "FromLocation": s.from_location, "FromRmp": s.from_rmp, "ToLocation": s.to_location, "ToRmp": s.to_rmp}
    return {k: esc(v) for k, v in raw.items()}
