"""Range consolidation — cells to compact Excel range strings.

Uses the same greedy rectangle expansion algorithm as the TypeScript
and Python backend implementations (rectangle_consolidation).
"""

from __future__ import annotations

from shortcut_xl.api.utils.helpers import index_to_address


def consolidate_ranges(cells: list[tuple[int, int]]) -> list[str]:
    """Convert a list of (row, col) tuples into compact Excel range strings.

    Sorts cells by Manhattan distance to (0, 0) and greedily expands
    rectangles from each uncovered top-left corner.  Matches the shared
    ``consolidateCellsIntoRectangles`` algorithm used by the TypeScript
    and Python backend implementations.
    """
    if not cells:
        return []

    if len(cells) == 1:
        r, c = cells[0]
        return [index_to_address(r, c)]

    cell_set = {f'{r},{c}' for r, c in cells}
    covered: set[str] = set()
    ranges: list[str] = []

    # Sort by Manhattan distance to (0, 0)
    sorted_cells = sorted(cells, key=lambda rc: rc[0] + rc[1])

    for r, c in sorted_cells:
        key = f'{r},{c}'
        if key in covered:
            continue

        # Expand rectangle greedily from (r, c)
        er, ec = r, c

        while True:
            can_right = _can_expand_col(r, er, ec, cell_set, covered)
            if can_right:
                ec += 1

            # Re-check down with the (possibly updated) ec
            can_down = _can_expand_row(r, c, er, ec, cell_set, covered)
            if can_down:
                er += 1

            if not can_right and not can_down:
                break

        # Mark rectangle cells as covered
        for rr in range(r, er + 1):
            for cc in range(c, ec + 1):
                covered.add(f'{rr},{cc}')

        if r == er and c == ec:
            ranges.append(index_to_address(r, c))
        else:
            ranges.append(f'{index_to_address(r, c)}:{index_to_address(er, ec)}')

    return ranges


def _can_expand_col(
    start_row: int,
    end_row: int,
    end_col: int,
    cell_set: set[str],
    covered: set[str],
) -> bool:
    """Check if adding the next column to the right is valid."""
    nc = end_col + 1
    for row in range(start_row, end_row + 1):
        key = f'{row},{nc}'
        if key not in cell_set or key in covered:
            return False
    return True


def _can_expand_row(
    start_row: int,
    start_col: int,
    end_row: int,
    end_col: int,
    cell_set: set[str],
    covered: set[str],
) -> bool:
    """Check if adding the next row below is valid."""
    nr = end_row + 1
    for col in range(start_col, end_col + 1):
        key = f'{nr},{col}'
        if key not in cell_set or key in covered:
            return False
    return True
