from collections.abc import Iterable

import numpy as np


def make_vector(
    x: float | Iterable[float], length: int, dtype: str | np.dtype
) -> np.ndarray:
    if isinstance(x, float):
        return np.array([x] * int(length), dtype=dtype)
    result = np.array(x, dtype=dtype)
    if len(result.shape) != 1:
        raise ValueError(
            "Cannot make a 1-D vector."
            " The argument implies shape: " + repr(result.shape)
        )
    if len(result) != length:
        raise ValueError(
            "Cannot make a 1-D vector of length "
            + repr(length)
            + ". The argument implies length: "
            + repr(len(result))
        )
    return result


def readonly_view(x: np.ndarray) -> np.ndarray:
    x = x[:]
    x.flags.writeable = False
    return x


def positive_float_or_none(x: float | None) -> float | None:
    if x is None:
        return None
    x = float(x)
    if x <= 0.0:
        x = None
    return x


def positive_float(x: float) -> float:
    org_x = x
    x = float(x)
    if x <= 0:
        raise ValueError(
            "Expected a positive real number, but received: " + repr(org_x)
        )
    return x


def positive_int(x: int) -> int:
    org_x = x
    x = int(x)
    if x <= 0:
        raise ValueError("Expected a positive integer, but received: " + repr(org_x))
    return x


def non_negative_float(x: float) -> float:
    org_x = x
    x = float(x)
    if x < 0:
        raise ValueError(
            "Expected a non-negative real number, but received: " + repr(org_x)
        )
    return x
