"""CRC-16/IBM (a.k.a. CRC-16/ARC).

Per ``docs/teltonika/03-protocols.md`` §3, every Teltonika TCP AVL
frame ends with a 4-byte CRC field whose **low 16 bits** carry the
CRC-16/IBM checksum over bytes from the Codec ID through NumData2;
the high 16 bits are reserved zero. Algorithm parameters (from the
wiki):

  * Polynomial:    ``0xA001`` (reversed representation of ``0x8005``)
  * Init:          ``0x0000``
  * Reflect input: yes (implicit in the reversed-poly form)
  * Reflect output: yes (same)
  * Final XOR:     ``0x0000``

The reference implementation in the protocol doc is the ground truth;
this module is a one-line restatement of it. No table lookup —
deliberately readable over fast; the codec's hot path is in
:mod:`plasmamapper.providers.telematics.teltonika.codec`, not here.
If a future benchmark shows CRC dominates, swap in a precomputed
table; the input bytes per frame are bounded (~1500 typical, ~16k
worst-case) so the simple version is fine for Phase 2.
"""

from __future__ import annotations

__all__ = ["crc16_ibm"]


def crc16_ibm(data: bytes) -> int:
    """Compute CRC-16/IBM over ``data``. Returns an int in ``0..0xFFFF``."""
    crc = 0
    for byte in data:
        crc ^= byte
        for _ in range(8):
            crc = (crc >> 1) ^ 0xA001 if crc & 1 else crc >> 1
    return crc & 0xFFFF
