from datetime import (
    datetime,
    time,
)

import pytest

import freezegun
from assertpy import assert_that
from maintenance_util import MaintenanceWindow


@pytest.mark.parametrize(
    argnames=("start_hour", "end_hour", "current_hour", "result"),
    argvalues=(
        (4, 6, 5, True),
        (4, 6, 3, False),
        (4, 6, 7, False),
        (22, 4, 23, True),
        (22, 4, 3, True),
        (22, 4, 21, False),
        (22, 4, 5, False),
    ),
    ids=(
        "same day inside",
        "same day before",
        "same day after",
        "different days after start",
        "different days before end",
        "different days before start",
        "different days after end",
    )
)
def test_is_inside(start_hour, end_hour, current_hour, result):
    window = MaintenanceWindow(
        start_time=time(hour=start_hour, minute=0, second=0, microsecond=0),
        end_time=time(hour=end_hour, minute=0, second=0, microsecond=0),
    )
    now = datetime.now()

    with freezegun.freeze_time(now.replace(hour=current_hour)):
        assert_that(window.is_inside()).is_equal_to(result)


@pytest.mark.parametrize(
    argnames=("start_hour", "end_hour", "current_hour", "expected_hours"),
    argvalues=(
        (4, 6, 5, 23),
        (4, 6, 3, 1),
        (4, 6, 7, 21),
        (22, 4, 23, 23),
        (22, 4, 3, 19),
        (22, 4, 21, 1),
        (22, 4, 5, 17),
    ),
    ids=(
        "same day inside",
        "same day before",
        "same day after",
        "different days after start",
        "different days before end",
        "different days before start",
        "different days after end",
    )
)
def test_seconds_until_next(start_hour, end_hour, current_hour, expected_hours):
    window = MaintenanceWindow(
        start_time=time(hour=start_hour, minute=0, second=0, microsecond=0),
        end_time=time(hour=end_hour, minute=0, second=0, microsecond=0),
    )
    now = datetime.now().replace(minute=0, second=0, microsecond=0)

    with freezegun.freeze_time(now.replace(hour=current_hour)):
        assert_that(window.seconds_to_next()).is_equal_to(expected_hours * 3600)


def test_boundaries_are_inclusive():
    start_time = time(hour=4, minute=0, second=0, microsecond=0)
    end_time = time(hour=6, minute=0, second=0, microsecond=0)
    window = MaintenanceWindow(
        start_time=start_time,
        end_time=end_time,
    )
    now = datetime.now().replace(
        hour=start_time.hour,
        minute=start_time.minute,
        second=start_time.second,
        microsecond=start_time.microsecond,
    )
    with freezegun.freeze_time(now):
        assert_that(window.is_inside()).is_true()

    now = datetime.now().replace(
        hour=end_time.hour,
        minute=end_time.minute,
        second=end_time.second,
        microsecond=end_time.microsecond,
    )
    with freezegun.freeze_time(now):
        assert_that(window.is_inside()).is_true()
