# Copyright (c) 2020 CloudZero - ALL RIGHTS RESERVED - PROPRIETARY AND CONFIDENTIAL
# Unauthorized copying of this file and/or project, via any medium is strictly prohibited.
# Direct all questions to legal@cloudzero.com

from datetime import datetime
from decimal import ROUND_DOWN, Decimal
from time import time
from typing import SupportsFloat

from dateutil.parser import isoparse
from dateutil.tz import tzutc

PRECISION = 6
PRECISION_STRING = f'.{"".join(PRECISION * "0")}'


def parse_to_utc(iso_date: str) -> datetime:
    if not iso_date:
        raise TypeError(f'Invalid iso_date: "{iso_date}"')
    parsed_datetime = isoparse(iso_date)
    if parsed_datetime.tzinfo is None:
        return parsed_datetime.replace(tzinfo=tzutc())
    return parsed_datetime.astimezone(tz=tzutc())


def parse_to_utc_timestamp(iso_date: str) -> Decimal:
    if not iso_date or not isinstance(iso_date, str):
        raise TypeError(f'Invalid iso_date: "{iso_date}"')
    return Decimal(f'{parse_to_utc(iso_date).timestamp():.{PRECISION}f}')


def timestamp_to_utc_datetime(timestamp: SupportsFloat) -> datetime:
    if not timestamp:
        raise TypeError(f'Invalid timestamp: "{timestamp}"')
    return datetime.fromtimestamp(float(timestamp), tz=tzutc())


def timestamp_to_utc_iso(timestamp: SupportsFloat) -> str:
    if not timestamp:
        raise TypeError(f'Invalid timestamp: "{timestamp}"')
    return timestamp_to_utc_datetime(timestamp).isoformat()


def get_current_timestamp() -> Decimal:
    return Decimal(str(time())).quantize(Decimal(PRECISION_STRING), rounding=ROUND_DOWN)


def get_current_utc_datetime() -> datetime:
    return datetime.fromtimestamp(float(get_current_timestamp()), tz=tzutc())


# Legacy API
iso_string_to_utc_datetime = parse_to_utc
iso_string_to_timestamp = parse_to_utc_timestamp
timestamp_to_iso_string = timestamp_to_utc_iso
