"""文档 12.6 日期时间字段对照表与逐条判定规则。"""
import datetime as dt
from dataclasses import dataclass
from zoneinfo import ZoneInfo

from flyway.domain.clock import NZ

FORM_CREATED = ("created the Load-In record", "created the Load-Out record", "created the Transfer record")
SLIP_CREATED = "created the packing slip record"
BATCH_MATCH = dt.timedelta(seconds=5)


@dataclass(frozen=True)
class Decision:
    resolution: str  # utc | user_nz | server | date | pending
    reason: str


def _server_is_nz(server_tz: ZoneInfo) -> bool:
    return server_tz.key == NZ.key


def decide_slip_date(slip: dict, server_tz: ZoneInfo) -> Decision:
    if _server_is_nz(server_tz):
        return Decision("user_nz", "server time zone is Pacific/Auckland")
    logs = slip.get("Logs") or ""
    if not logs.strip():
        return Decision("server", "created by packing from the load-out list (no Logs)")
    if SLIP_CREATED in logs:
        return Decision("user_nz", "created via the packing slip form (Logs)")
    return Decision("pending", "no evidence of the value's source")


def decide_transfer_date(row: dict, slips: dict, slip_decisions: dict, out_decisions: dict,
                         server_tz: ZoneInfo) -> Decision:
    if _server_is_nz(server_tz):
        return Decision("user_nz", "server time zone is Pacific/Auckland")
    if row.get("TransferFromId"):
        out = out_decisions.get(row["TransferFromId"])
        return Decision(out.resolution, "follows its transfer-out") if out else Decision("pending", "transfer-out unknown")
    slip_id = row.get("PackingSlipId")
    if slip_id in slips and row["Date"] == slips[slip_id]["Date"]:
        d = slip_decisions[slip_id]
        return Decision(d.resolution, f"date set by packing; {d.reason}")
    raw = row["Date"]
    if row.get("IsLoadOut") and (raw.second or raw.microsecond):
        # 表单只到分钟；带秒的出库日期可能是装箱写入的服务器时间（装箱不写 Logs，取消装箱后无从比对）
        return Decision("pending", "load-out date has seconds: may have been set by packing")
    if any(marker in (row.get("Logs") or "") for marker in FORM_CREATED):
        return Decision("user_nz", "created via form (Logs)")
    return Decision("pending", "no evidence of the value's source")


def decide_batch_date(row: dict, log_times: list[dt.datetime], server_tz: ZoneInfo) -> Decision:
    if _server_is_nz(server_tz):
        return Decision("user_nz", "server time zone is Pacific/Auckland")
    raw = row["Date"]
    if any(abs(raw - t) <= BATCH_MATCH for t in log_times):
        return Decision("server", "matches a Load-In log time (auto-created batch)")
    return Decision("pending", "no evidence of the value's source")


def apply(raw: dt.datetime, decision: Decision, server_tz: ZoneInfo) -> dt.datetime:
    zone = {"utc": dt.UTC, "user_nz": NZ, "server": server_tz, "pending": NZ}[decision.resolution]
    # ponytail: 夏令时重叠的那一小时取 fold=0（较早的时刻），迁移报告保留原值可追溯
    return raw.replace(tzinfo=zone)


def apply_date(raw: dt.datetime, decision: Decision, server_tz: ZoneInfo) -> dt.date:
    if decision.resolution == "date":
        return raw.date()
    return apply(raw, decision, server_tz).astimezone(NZ).date()
