"""Vector-level similarity and distance helpers."""

from __future__ import annotations

import numpy as np

from .ri import dense_l2_normalize


def cosine_similarity(vec_a: np.ndarray, vec_b: np.ndarray, assume_normalized: bool = True) -> float:
    """Compute cosine similarity for two dense vectors.

    When ``assume_normalized`` is true, the function uses a direct dot product.
    Otherwise both inputs are L2-normalized first, which is safer for vectors
    that may come from external composition steps.
    """
    a = np.asarray(vec_a, dtype=np.float32)
    b = np.asarray(vec_b, dtype=np.float32)

    if a.shape != b.shape:
        raise ValueError(f"Vector shapes must match: {a.shape} != {b.shape}")

    if not assume_normalized:
        a = dense_l2_normalize(a)
        b = dense_l2_normalize(b)

    return float(np.dot(a, b))


def l2_distance(vec_a: np.ndarray, vec_b: np.ndarray) -> float:
    """Compute Euclidean distance for two dense vectors."""
    a = np.asarray(vec_a, dtype=np.float32)
    b = np.asarray(vec_b, dtype=np.float32)

    if a.shape != b.shape:
        raise ValueError(f"Vector shapes must match: {a.shape} != {b.shape}")

    return float(np.linalg.norm(a - b))


def l2_normalize(vec: np.ndarray) -> np.ndarray:
    """Return an L2-normalized dense vector, preserving zero vectors."""
    arr = np.asarray(vec, dtype=np.float32)
    return dense_l2_normalize(arr)
