"""Util functions to convert between timestamp formats"""

from datetime import datetime, timedelta

try:
    from datetime import UTC
except ImportError:
    from datetime import timezone

    UTC = timezone.utc

from ..globals import MEASUREMENTS_PERIOD


def dt_obj_to_isodt_str(dt) -> str:
    """
    Convert datetime object to ISO 8601 string without timezone.

    :param datetime dt: datetime object in UTC timezone
    :returns: ISO 8601 string
    """
    return dt.replace(microsecond=0).replace(tzinfo=None).isoformat()


def isostr_to_dt_obj(isostr) -> datetime:
    return datetime.strptime(isostr, "%Y-%m-%dT%H:%M:%S").replace(tzinfo=UTC)


def unixts_to_dt_obj(unixts) -> datetime:
    """
    Convert unix timestamp to datetime object in UTC time zone.

    :param float/int/str unixts: unix timestamp
    :returns: datetime object in UTC timezone
    """
    if isinstance(unixts, str):
        try:
            unixts = int(unixts)
        except ValueError:
            unixts = float(unixts)
    if isinstance(unixts, float):
        unixts = int(unixts)
    return datetime.fromtimestamp(unixts, UTC)


def unixts_to_isodt_str(unixts) -> str:
    """
    Convert unix timestamp to ISO 8601 string in UTC time zone.

    :param float/int/str unixts: unix timestamp
    :returns: ISO 8601 string in UTC time zone
    """
    return dt_obj_to_isodt_str(unixts_to_dt_obj(unixts))


def now_unixts() -> float:
    return datetime.now(UTC).timestamp()


def now_isodt_str() -> str:
    """Return datetime now as ISO 8601 string in UTC time zone."""
    return dt_obj_to_isodt_str(datetime.now(UTC))


def now_fname() -> str:
    """
    Return now timestamp in UTC formatted as %Y%m%d_%H%M%S string for file
    names.

    :returns: now timestamp in UTC formatted as %Y%m%d_%H%M%S string
    """
    return datetime.now(UTC).strftime("%Y%m%d_%H%M%S")


def unixts_to_str(unixts) -> str:
    """Convert unix timestamp integer or float to string"""
    # even if it is only converting to str, ensure that input is nothing else
    # than int or float
    return str(unixts)


# XXX: tech-debt: replace all the code that check whether a
# measurement or relay is older than the measurement period by this.
def is_old(timestamp, measurements_period=MEASUREMENTS_PERIOD):
    """Whether the given timestamp is older that the given measurements
    period.
    """
    if not isinstance(timestamp, datetime):
        if isinstance(timestamp, str):
            # This will raise an exception if the string is not correctly
            # formatted.
            timestamp = isostr_to_dt_obj(timestamp)
        elif isinstance(timestamp, int) or isinstance(timestamp, float):
            # This will raise an exception if the type is not int or float or
            # is not actually a timestamp
            timestamp = unixts_to_dt_obj(timestamp)
    oldest_date = datetime.now(UTC) - timedelta(seconds=measurements_period)
    return timestamp < oldest_date
