"""Geometric utilities: bbox operations, 1D clustering."""
from __future__ import annotations
from ..types import BBox


def merge_bboxes(bboxes: list[BBox]) -> BBox:
    if not bboxes:
        raise ValueError("Cannot merge empty list of bboxes")
    return BBox(
        x0=min(b.x0 for b in bboxes),
        y0=min(b.y0 for b in bboxes),
        x1=max(b.x1 for b in bboxes),
        y1=max(b.y1 for b in bboxes),
    )


def cluster_1d(values: list[float], gap: float) -> list[list[int]]:
    """Cluster sorted values by gap threshold. Returns lists of original indices."""
    if not values:
        return []
    indexed = sorted(enumerate(values), key=lambda x: x[1])
    clusters: list[list[int]] = [[indexed[0][0]]]
    for i in range(1, len(indexed)):
        if indexed[i][1] - indexed[i - 1][1] > gap:
            clusters.append([])
        clusters[-1].append(indexed[i][0])
    return clusters


def horizontal_overlap(a: BBox, b: BBox) -> float:
    """Fraction of horizontal overlap relative to narrower box."""
    overlap = min(a.x1, b.x1) - max(a.x0, b.x0)
    if overlap <= 0:
        return 0.0
    return overlap / min(a.width, b.width) if min(a.width, b.width) > 0 else 0.0


def vertical_distance(a: BBox, b: BBox) -> float:
    """Vertical gap between two bboxes (negative means overlap)."""
    if a.y1 <= b.y0:
        return b.y0 - a.y1
    elif b.y1 <= a.y0:
        return a.y0 - b.y1
    else:
        return 0.0


def is_same_line(a: BBox, b: BBox, tolerance: float = 2.0) -> bool:
    """Check if two bboxes are on the same text line."""
    return abs(a.y0 - b.y0) < tolerance and abs(a.y1 - b.y1) < tolerance


def find_columns(x_positions: list[float], page_width: float, gap_threshold: float = 20.0) -> list[tuple[float, float]]:
    """Detect column boundaries from x-position distribution."""
    if not x_positions:
        return [(0, page_width)]
    mid = page_width / 2
    left = [x for x in x_positions if x < mid - gap_threshold]
    right = [x for x in x_positions if x > mid + gap_threshold]
    if left and right:
        left_max = max(left)
        right_min = min(right)
        if right_min - left_max > gap_threshold:
            return [(0, (left_max + right_min) / 2), ((left_max + right_min) / 2, page_width)]
    return [(0, page_width)]
