import torch


def distance2bbox(points, distance, max_shape=None):
    """Decode distance prediction to bounding box.

    Args:
        points (Tensor): Shape (n, 3), [t, x, y].
        distance (Tensor): Distance from the given point to 4
            boundaries (left, top, right, bottom, frDis, 4point, bkDis, 4point).
        max_shape (list): Shape of the image.

    Returns:
        Tensor: Decoded bboxes.
    """

    mid_t = points[:, 0]
    mid_x1 = points[:, 1] - distance[:, 0]
    mid_y1 = points[:, 2] - distance[:, 1]
    mid_x2 = points[:, 1] + distance[:, 2]
    mid_y2 = points[:, 2] + distance[:, 3]

    fr_t = points[:, 0] + distance[:, 4]
    fr_x1 = mid_x1 + distance[:, 5]
    fr_y1 = mid_y1 + distance[:, 6]
    fr_x2 = mid_x2 + distance[:, 7]
    fr_y2 = mid_y2 + distance[:, 8]

    bk_t = points[:, 0] - distance[:, 9]
    bk_x1 = mid_x1 + distance[:, 10]
    bk_y1 = mid_y1 + distance[:, 11]
    bk_x2 = mid_x2 + distance[:, 12]
    bk_y2 = mid_y2 + distance[:, 13]

    if max_shape is not None:
        mid_x1 = mid_x1.clamp(min=0, max=max_shape[2])
        mid_y1 = mid_y1.clamp(min=0, max=max_shape[1])
        mid_x2 = mid_x2.clamp(min=0, max=max_shape[2])
        mid_y2 = mid_y2.clamp(min=0, max=max_shape[1])

        fr_t = fr_t.clamp(min=0, max=max_shape[0])
        fr_x1 = fr_x1.clamp(min=0, max=max_shape[2])
        fr_y1 = fr_y1.clamp(min=0, max=max_shape[1])
        fr_x2 = fr_x2.clamp(min=0, max=max_shape[2])
        fr_y2 = fr_y2.clamp(min=0, max=max_shape[1])

        bk_t = bk_t.clamp(min=0, max=max_shape[0])
        bk_x1 = bk_x1.clamp(min=0, max=max_shape[2])
        bk_y1 = bk_y1.clamp(min=0, max=max_shape[1])
        bk_x2 = bk_x2.clamp(min=0, max=max_shape[2])
        bk_y2 = bk_y2.clamp(min=0, max=max_shape[1])

    return torch.stack([mid_t, mid_x1, mid_y1, mid_x2, mid_y2,
                        fr_t, fr_x1, fr_y1, fr_x2, fr_y2,
                        bk_t, bk_x1, bk_y1, bk_x2, bk_y2], -1)