def merge_intervals(intervals: list[list[int]]) -> list[list[int]]:
    """
    Merge all overlapping intervals.

    Each interval is represented as a list of two integers [start, end].
    The function merges overlapping intervals and returns a list of
    non-overlapping intervals sorted by start time.

    Parameters:
    intervals (list[list[int]]): A list of intervals.

    Returns:
    list[list[int]]: A list of merged non-overlapping intervals.

    Edge Cases Handled:
    - Empty list: returns []
    - Single interval: returns the interval itself
    - Intervals already sorted or unsorted
    - Fully overlapping intervals
    - Invalid intervals (e.g., [[]] or intervals not having exactly
      2 integers) raise ValueError

    Examples:
    >>> merge_intervals([[1, 3], [2, 6], [8, 10], [15, 18]])
    [[1, 6], [8, 10], [15, 18]]
    >>> merge_intervals([[1, 4], [4, 5]])
    [[1, 5]]
    >>> merge_intervals([[6, 8], [1, 3], [2, 4]])
    [[1, 4], [6, 8]]
    >>> merge_intervals([])
    []
    >>> merge_intervals([[1, 4]])
    [[1, 4]]

    Time Complexity:
    O(n log n) - sorting the intervals, where n is the number of intervals.

    Space Complexity:
    O(n) - storing the merged intervals.
    """

    if not intervals:
        return []

    for interval in intervals:
        msg = f"Each interval must have exactly 2 integers, got {interval}"
        if len(interval) != 2:
            raise ValueError(msg)

    # Sort intervals based on the start time
    # Sort a copy so the caller's list (and its inner lists) are never mutated
    sorted_intervals = sorted(intervals, key=lambda interval: interval[0])

    merged: list[list[int]] = [sorted_intervals[0][:]]

    for current in sorted_intervals[1:]:
        last = merged[-1]

        # If current interval overlaps with the last merged interval
        if current[0] <= last[1]:
            last[1] = max(last[1], current[1])
        else:
            merged.append(current[:])
    return merged
