from uuid import UUID as BaseUUID
from uuid import SafeUUID


class UUID(BaseUUID):
    def __init__(
        self,
        hex: str | None = None,
        bytes: bytes | None = None,
        bytes_le: bytes | None = None,
        fields: tuple[int, int, int, int, int, int] | None = None,
        int: int | None = None,
        version: int | None = None,
        *,
        is_safe: SafeUUID = SafeUUID.unknown
    ) -> None:
        super().__init__(
            hex, bytes, bytes_le, fields, int, version=None, is_safe=is_safe
        )

        if version is not None:
            if not 1 <= version <= 7:
                raise ValueError("illegal version number")
            # Set the variant to RFC 4122.
            int = int or 0
            int &= ~(0xC000 << 48)
            int |= 0x8000 << 48
            # Set the version number.
            int &= ~(0xF000 << 64)
            int |= version << 76
        object.__setattr__(self, "int", int)
        object.__setattr__(self, "is_safe", is_safe)


_last_v6_timestamp = None
_last_v7_timestamp = None


def uuid6(clock_seq=None):
    """Generate a UUID from sequence number, and the current time.
    If 'clock_seq' is given, it is used as the sequence number;
    otherwise a random 14-bit sequence number is chosen."""

    global _last_v6_timestamp
    import random
    import time

    nanoseconds = time.time_ns()
    # 0x01b21dd213814000 is the number of 100-ns intervals between the
    # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
    timestamp = nanoseconds // 100 + 0x01B21DD213814000
    if _last_v6_timestamp is not None and timestamp <= _last_v6_timestamp:
        timestamp = _last_v6_timestamp + 1
    _last_v6_timestamp = timestamp
    if clock_seq is None:
        clock_seq = random.SystemRandom().getrandbits(
            14
        )  # instead of stable storage
    node = random.SystemRandom().getrandbits(48)
    time_high_and_time_mid = (timestamp >> 12) & 0xFFFFFFFFFFFF
    time_low_and_version = timestamp & 0x0FFF
    uuid_int = time_high_and_time_mid << 80
    uuid_int += time_low_and_version << 64
    uuid_int += (clock_seq & 0x3FFF) << 48
    uuid_int += node
    return UUID(int=uuid_int, version=6)


def uuid7():
    """The UUIDv7 format is designed to encode a Unix timestamp with
    arbitrary sub-second precision.  The key property provided by UUIDv7
    is that timestamp values generated by one system and parsed by
    another are guaranteed to have sub-second precision of either the
    generator or the parser, whichever is less.  Additionally, the system
    parsing the UUIDv7 value does not need to know which precision was
    used during encoding in order to function correctly."""

    global _last_v7_timestamp
    import random
    import time

    nanoseconds = time.time_ns()
    if _last_v7_timestamp is not None and nanoseconds <= _last_v7_timestamp:
        nanoseconds = _last_v7_timestamp + 1
    _last_v7_timestamp = nanoseconds
    timestamp_s, timestamp_ns = divmod(nanoseconds, 10**9)
    subsec_a = timestamp_ns >> 18
    subsec_b = (timestamp_ns >> 6) & 0x0FFF
    subsec_seq_node = (timestamp_ns & 0x3F) << 56
    subsec_seq_node += random.SystemRandom().getrandbits(56)
    uuid_int = (timestamp_s & 0x0FFFFFFFFF) << 92
    uuid_int += subsec_a << 80
    uuid_int += subsec_b << 64
    uuid_int += subsec_seq_node
    return UUID(int=uuid_int, version=7)
