"""Wall-clock helpers for Medulla tick filtering.

Two tick conventions appear in this dataset:

- LiDAR DObject ``tic`` / recovered ``indices.log``: ``DateTime.Now.Ticks`` (local)
- IMU / MSOP payload host receive fields: UTC ``DateTime.UtcNow.Ticks``
"""

from __future__ import annotations

from datetime import datetime, timedelta, timezone

TICKS_PER_SECOND = 10_000_000
DOTNET_UNIX_EPOCH_TICKS = 621355968000000000


def _parse_local_wall(text: str) -> datetime:
    normalized = text.strip().replace(" ", "T")
    if normalized.endswith("Z"):
        raise ValueError("expected local wall time without Z; got UTC marker")
    if "+" in normalized[10:]:
        idx = normalized.find("+", 10)
        normalized = normalized[:idx]
    elif normalized.count("-") > 2:
        # timezone like -08:00 after the date
        idx = normalized.find("-", 10)
        if idx > 0 and ":" in normalized[idx + 1 :]:
            normalized = normalized[:idx]
    return datetime.fromisoformat(normalized).replace(tzinfo=None)


def local_wall_to_dotnet_ticks(text: str) -> int:
    """Local wall time → ``DateTime.Now.Ticks`` (LiDAR DObject tic)."""

    dt = _parse_local_wall(text)
    delta = dt - datetime(1, 1, 1)
    return int(delta.total_seconds() * TICKS_PER_SECOND)


def local_wall_to_utc_dotnet_ticks(text: str, *, tz_hours: float = 8.0) -> int:
    """Local wall time in ``tz_hours`` → UTC ``DateTime.UtcNow.Ticks`` (IMU host)."""

    dt = _parse_local_wall(text).replace(tzinfo=timezone(timedelta(hours=tz_hours)))
    unix = dt.timestamp()
    return int(round(unix * TICKS_PER_SECOND)) + DOTNET_UNIX_EPOCH_TICKS


def dotnet_ticks_to_local_iso(ticks: int) -> str:
    dt = datetime(1, 1, 1) + timedelta(microseconds=ticks / 10.0)
    return dt.isoformat(timespec="milliseconds")


def utc_dotnet_ticks_to_unix_s(ticks: int) -> float:
    """UTC ``DateTime.UtcNow.Ticks`` → Unix seconds."""

    return (float(ticks) - float(DOTNET_UNIX_EPOCH_TICKS)) / float(TICKS_PER_SECOND)
