import struct
from datetime import datetime


def dzt_header_date(date_bytes):
    """Transform 4 (dense) bytes to datetime following the DZT-date format.

    Parameters
    ----------
    date_bytes : bytes
        4 byte long bytes object.

    Returns
    -------
    date : datetime
        Date in datetime format.
    date tuple: tuple
        In a case if datetime object is not well defined.
        Tuple format = (year + 1980, month, day, hour, minutes, seconds=sec*2)

    """
    # Little endian binary --> number to binary array with [::-1]
    binary_array = format(struct.unpack("<I", date_bytes)[0], "b").zfill(32)[::-1]

    # Transform array back to number with [::-1]
    # Values are uint --> python int with binary repr will work
    sec2 = int(binary_array[0:5][::-1], base=2)  # 5-bits 00-04  0-29 (second/2)
    minutes = int(binary_array[5:11][::-1], base=2)  # 6-bits 05-10  0-59
    hour = int(binary_array[11:16][::-1], base=2)  # 5-bits 11-15  0-23
    day = int(binary_array[16:21][::-1], base=2)  # 5-bits 16-20  1-31
    month = int(binary_array[21:25][::-1], base=2)  # 4-bits 21-24  1-12, 1=Jan, 2=Feb, etc.
    year = int(binary_array[25:32][::-1], base=2)  # 7-bits 25-31  0-127 (0-127 = 1980-2107)

    value_range_pairs = (
        (sec2, (0, 30)),
        (minutes, (0, 60)),
        (hour, (0, 24)),
        (day, (1, 32)),
        (month, (1, 13)),
        (year, (0, 128)),
    )

    if all((v >= lb) & (v < ub) for v, (lb, ub) in value_range_pairs):
        return datetime(1980 + year, month, day, hour, minutes, sec2 * 2)
    return (1980 + year, month, day, hour, minutes, sec2 * 2)