# -*- mode: python; coding: utf-8 -*-
# Copyright 2016 the HERA Collaboration
# Licensed under the 2-clause BSD license.

"""Testing for `hera_mc.server_status`.

"""
from math import floor

import pytest
from astropy.time import Time, TimeDelta

from ..librarian import LibServerStatus
from ..rtp import RTPServerStatus


@pytest.fixture(scope="module")
def status():
    class DataHolder(object):
        column_names = [
            "hostname",
            "mc_time",
            "ip_address",
            "system_time",
            "num_cores",
            "cpu_load_pct",
            "uptime_days",
            "memory_used_pct",
            "memory_size_gb",
            "disk_space_pct",
            "disk_size_gb",
            "network_bandwidth_mbs",
        ]
        column_values = [
            "test_host",
            Time.now(),
            "0.0.0.0",
            Time.now(),
            16,
            20.5,
            31.4,
            43.2,
            32.0,
            46.8,
            510.4,
            10.4,
        ]
        columns = dict(zip(column_names, column_values))

    data = DataHolder()

    # yields the data we need but will continue to the del call after tests
    yield data

    # some post-test object cleanup
    del data

    return


def test_repr(status):
    for sub in ["rtp", "lib"]:
        exp_columns = status.columns.copy()
        exp_columns["mc_time"] = int(floor(exp_columns["mc_time"].gps))
        exp_columns.pop("system_time")
        exp_columns["mc_system_timediff"] = 0

        if sub == "rtp":
            servstat = RTPServerStatus(**exp_columns)
            class_name = "RTPServerStatus"
        elif sub == "lib":
            servstat = LibServerStatus(**exp_columns)
            class_name = "LibServerStatus"

    rep_string = (
        "<"
        + class_name
        + "(test_host, "
        + str(exp_columns["mc_time"])
        + ", 0.0.0.0, "
        + str(exp_columns["mc_system_timediff"])
        + ", 16, 20.5, 31.4, 43.2, 32.0, 46.8, 510.4, 10.4)>"
    )
    assert str(servstat) == rep_string


def test_add_server_status(mcsession, status):
    test_session = mcsession
    for sub in ["rtp", "lib"]:
        exp_columns = status.columns.copy()
        exp_columns["mc_time"] = int(floor(Time.now().gps))
        exp_columns["mc_system_timediff"] = (
            exp_columns["mc_time"] - exp_columns["system_time"].gps
        )
        exp_columns.pop("system_time")

        if sub == "rtp":
            expected = RTPServerStatus(**exp_columns)
        elif sub == "lib":
            expected = LibServerStatus(**exp_columns)

        test_session.add_server_status(
            sub,
            status.column_values[0],
            *status.column_values[2:11],
            network_bandwidth_mbs=status.column_values[11]
        )
        result = test_session.get_server_status(
            sub, starttime=(status.columns["system_time"] - TimeDelta(2, format="sec"))
        )
        assert len(result) == 1
        result = result[0]

        if sub == "rtp":
            result = test_session.get_rtp_server_status(
                sub,
                starttime=status.columns["system_time"] - TimeDelta(2, format="sec"),
            )
        else:
            result = test_session.get_librarian_server_status(
                sub,
                starttime=status.columns["system_time"] - TimeDelta(2, format="sec"),
            )
        assert len(result) == 1
        result = result[0]

        # mc_system_timediff may not be identical. Check that they are close
        # and set them equal so the rest of the object can be tested
        mc_system_timediff_diff = abs(
            result.mc_system_timediff - expected.mc_system_timediff
        )
        assert mc_system_timediff_diff < 2
        if mc_system_timediff_diff > 0.001:
            expected.mc_system_timediff = result.mc_system_timediff

        # mc_time might be off by one between expected & result because of the
        # time between the commands
        mc_timediff = abs(result.mc_time - expected.mc_time)
        assert mc_timediff < 2
        if mc_timediff > 0.001:
            expected.mc_time = result.mc_time

        assert result.isclose(expected)

        test_session.add_server_status(
            sub,
            "test_host2",
            *status.column_values[2:11],
            network_bandwidth_mbs=status.column_values[11]
        )
        result_host = test_session.get_server_status(
            sub,
            starttime=(status.columns["system_time"] - TimeDelta(2, format="sec")),
            hostname=status.columns["hostname"],
            stoptime=(status.columns["system_time"] + TimeDelta(2 * 60, format="sec")),
        )
        assert len(result_host) == 1
        result_host = result_host[0]
        assert result_host.isclose(expected)

        result_mult = test_session.get_server_status(
            sub,
            starttime=(status.columns["system_time"] - TimeDelta(2, format="sec")),
            stoptime=(status.columns["system_time"] + TimeDelta(2 * 60, format="sec")),
        )

        assert len(result_mult) == 2

        result2 = test_session.get_server_status(
            sub,
            starttime=(status.columns["system_time"] - TimeDelta(2, format="sec")),
            hostname="test_host2",
        )[0]
        # mc_times will be different, so won't match. set them equal so that
        # we can test the rest
        expected.mc_time = result2.mc_time
        assert not result2.isclose(expected)


def test_errors_server_statuss(mcsession, status):
    test_session = mcsession
    for sub in ["rtp", "lib"]:
        pytest.raises(
            ValueError,
            test_session.add_server_status,
            sub,
            status.column_values[0],
            status.column_values[2],
            "foo",
            *status.column_values[4:11],
            network_bandwidth_mbs=status.column_values[11]
        )

        test_session.add_server_status(
            sub,
            status.column_values[0],
            *status.column_values[2:11],
            network_bandwidth_mbs=status.column_values[11]
        )
        pytest.raises(
            ValueError, test_session.get_server_status, sub, starttime="test_host"
        )
        pytest.raises(
            ValueError,
            test_session.get_server_status,
            sub,
            starttime=status.columns["system_time"],
            stoptime="test_host",
        )

        if sub == "rtp":
            pytest.raises(
                ValueError,
                RTPServerStatus.create,
                "foo",
                status.column_values[0],
                *status.column_values[2:11],
                network_bandwidth_mbs=status.column_values[11]
            )
        elif sub == "lib":
            pytest.raises(
                ValueError,
                LibServerStatus.create,
                "foo",
                status.column_values[0],
                *status.column_values[2:11],
                network_bandwidth_mbs=status.column_values[11]
            )

    pytest.raises(
        ValueError,
        test_session.add_server_status,
        "foo",
        status.column_values[0],
        *status.column_values[2:11],
        network_bandwidth_mbs=status.column_values[11]
    )
    pytest.raises(
        ValueError,
        test_session.get_server_status,
        "foo",
        starttime=status.column_values[1],
    )
