import datetime as dt
import uuid
from zoneinfo import ZoneInfo

from flyway.domain.clock import NZ
from flyway.migration.dates import (
    Decision, apply, apply_date, decide_batch_date, decide_slip_date, decide_transfer_date,
)

UTC = ZoneInfo("UTC")
RAW = dt.datetime(2024, 10, 8, 15, 0)


def test_server_in_nz_needs_no_per_row_decision():
    assert decide_slip_date({"Logs": None}, NZ).resolution == "user_nz"


def test_slip_without_logs_is_server_generated():
    assert decide_slip_date({"Logs": ""}, UTC).resolution == "server"
    assert decide_slip_date({"Logs": "x <b>a</b> created the packing slip record P1"}, UTC).resolution == "user_nz"
    assert decide_slip_date({"Logs": "x <b>a</b> edited the content of P1"}, UTC).resolution == "pending"


def test_transfer_date_rules():
    slip_id = uuid.uuid4()
    slips = {slip_id: {"Date": RAW}}
    slip_decisions = {slip_id: Decision("server", "no logs")}
    packed = {"ID": uuid.uuid4(), "TransferFromId": None, "PackingSlipId": slip_id, "Date": RAW, "Logs": ""}
    assert decide_transfer_date(packed, slips, slip_decisions, {}, UTC).resolution == "server"
    created = {"ID": uuid.uuid4(), "TransferFromId": None, "PackingSlipId": None, "Date": RAW,
               "Logs": "t <b>a</b> created the Load-Out record LO"}
    assert decide_transfer_date(created, slips, slip_decisions, {}, UTC).resolution == "user_nz"
    out_id = uuid.uuid4()
    twin = {"ID": uuid.uuid4(), "TransferFromId": out_id, "PackingSlipId": None, "Date": RAW, "Logs": None}
    assert decide_transfer_date(twin, slips, slip_decisions, {out_id: Decision("user_nz", "x")}, UTC).resolution == "user_nz"
    unknown = {"ID": uuid.uuid4(), "TransferFromId": None, "PackingSlipId": None, "Date": RAW, "Logs": None}
    assert decide_transfer_date(unknown, slips, slip_decisions, {}, UTC).resolution == "pending"


def test_batch_date_matches_load_in_log_time():
    log_times = [dt.datetime(2024, 10, 8, 15, 0, 3)]
    assert decide_batch_date({"Date": RAW}, log_times, UTC).resolution == "server"
    assert decide_batch_date({"Date": RAW - dt.timedelta(minutes=1)}, log_times, UTC).resolution == "pending"


def test_apply_converts_by_resolution():
    assert apply(RAW, Decision("utc", ""), UTC) == RAW.replace(tzinfo=dt.UTC)
    assert apply(RAW, Decision("user_nz", ""), UTC) == RAW.replace(tzinfo=NZ)
    # UTC 15:00 = 新西兰 10-09 04:00（夏令时 +13）
    assert apply_date(RAW, Decision("server", ""), UTC) == dt.date(2024, 10, 9)
    assert apply_date(RAW, Decision("date", ""), UTC) == dt.date(2024, 10, 8)


def test_form_created_load_out_with_seconds_is_pending():
    # 装箱会把出库单日期改成服务器时间且不写日志；取消装箱后无法与装箱单比对
    row = {"ID": uuid.uuid4(), "TransferFromId": None, "PackingSlipId": None, "IsLoadOut": True,
           "Date": RAW.replace(second=7, microsecond=120000), "Logs": "t <b>a</b> created the Load-Out record LO"}
    assert decide_transfer_date(row, {}, {}, {}, UTC).resolution == "pending"
    row["Date"] = RAW
    assert decide_transfer_date(row, {}, {}, {}, UTC).resolution == "user_nz"
