# Copyright (c) 2022 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 Decimal
from time import time

import pytest
from dateutil.tz import tzlocal, tzutc
from freezegun import freeze_time

from czc import date

now = datetime.fromtimestamp(float(Decimal(time()).quantize(Decimal('.000000'))), tz=tzutc())
now_timestamp_decimal = Decimal(now.timestamp()).quantize(Decimal('.000000'))
now_local_offset = now.astimezone(tz=tzlocal())


@pytest.mark.unit
@freeze_time(now)
@pytest.mark.parametrize('date_fn, args, expected', [
    pytest.param('parse_to_utc', [now.isoformat()], now, id='parse_to_utc'),
    pytest.param('parse_to_utc_timestamp', [now.isoformat()], now_timestamp_decimal, id='parse_to_utc_timestamp'),
    pytest.param('timestamp_to_utc_datetime', [now.timestamp()], now, id='timestamp_to_utc_datetime'),
    pytest.param('timestamp_to_utc_iso', [now.timestamp()], now.isoformat(), id='timestamp_to_utc_iso'),
    pytest.param('get_current_timestamp', [], now_timestamp_decimal, id='get_current_timestamp'),
    pytest.param('get_current_utc_datetime', [], now, id='get_current_utc_datetime'),
])
def test_all_functions_return_correct_time(date_fn, args, expected):
    result = getattr(date, date_fn)(*args)
    assert result == expected


@pytest.mark.unit
@freeze_time(now)
@pytest.mark.parametrize('date_fn, args, exception', [
    pytest.param('parse_to_utc', [None], TypeError, id='parse_to_utc TypeError on None'),
    pytest.param('parse_to_utc', ['bad string'], ValueError, id='parse_to_utc ValueError on badstring'),
    pytest.param('parse_to_utc_timestamp', [None], TypeError, id='parse_to_utc_timestamp TypeError on None'),
    pytest.param('parse_to_utc_timestamp', ['bad string'], ValueError, id='parse_to_utc_timestamp ValueError on badstring'),
    pytest.param('timestamp_to_utc_datetime', [None], TypeError, id='timestamp_to_utc_datetime TypeError on None'),
    pytest.param('timestamp_to_utc_datetime', ['bad timestamp'], ValueError, id='timestamp_to_utc_datetime ValueError on bad timestamp'),
    pytest.param('timestamp_to_utc_iso', [None], TypeError, id='timestamp_to_utc_iso TypeError on None'),
    pytest.param('timestamp_to_utc_iso', ['bad timestamp'], ValueError, id='timestamp_to_utc_iso ValueError on bad timestamp'),
])
def test_all_functions_throw_expected_exceptions_on_bad_input(date_fn, args, exception):
    with pytest.raises(exception):
        getattr(date, date_fn)(*args)


@pytest.mark.unit
@freeze_time(now)
@pytest.mark.parametrize('date_fn, expected', [
    pytest.param('parse_to_utc', now, id='parse_to_utc'),
    pytest.param('parse_to_utc_timestamp', now_timestamp_decimal, id='parse_to_utc_timestamp'),
])
@pytest.mark.parametrize('args', [
    pytest.param([now.isoformat()], id='UTC iso string'),
    pytest.param([now.replace(tzinfo=None).isoformat()], id='naive iso string'),
    pytest.param([now_local_offset.isoformat()], id='non-UTC iso string'),
])
def test_parse_to_utc_functions_correctly_convert_tz_aware_iso_strings(date_fn, expected, args):
    result = getattr(date, date_fn)(*args)
    assert result == expected
