"""Conversion helpers for BPM and note durations."""


def _validate_positive_number(value: float, label: str) -> float:
    try:
        numeric_value = float(value)
    except (TypeError, ValueError) as exc:
        raise ValueError(f"{label} must be a number.") from exc

    if numeric_value <= 0:
        raise ValueError(f"{label} must be greater than 0.")

    return numeric_value


def _validate_note_division(note_division: int) -> int:
    if isinstance(note_division, bool):
        raise ValueError("note_division must be a positive integer.")

    try:
        division = int(note_division)
    except (TypeError, ValueError) as exc:
        raise ValueError("note_division must be a positive integer.") from exc

    if division <= 0:
        raise ValueError("note_division must be a positive integer.")

    return division


def bpm_to_ms(bpm: float, note_division: int = 1) -> float:
    """Convert BPM to milliseconds for a note length denominator.

    A note division of 4 represents a quarter note, 8 an eighth note,
    and 1 a whole note.
    """

    bpm_value = _validate_positive_number(bpm, "bpm")
    division = _validate_note_division(note_division)
    milliseconds = 240000.0 / (bpm_value * division)
    return round(milliseconds, 2)


def ms_to_bpm(milliseconds: float, note_division: int = 1) -> float:
    """Convert milliseconds for a note length denominator back to BPM."""

    duration = _validate_positive_number(milliseconds, "milliseconds")
    division = _validate_note_division(note_division)
    bpm_value = 240000.0 / (duration * division)
    return round(bpm_value, 2)

