import datetime

import pytest

from ... import errors
from ..._icat_messaging.serializers.dataset_parameters.fallback import (
    fallback_serialization,
)
from ..._icat_messaging.utils import datetime_utils


@pytest.mark.parametrize(
    "input_data, expected",
    [
        ({}, {}),
        ({"key": None}, {}),
        ({"key": "string"}, {"key": "string"}),
        ({"key": b"string"}, {"key": "string"}),
        ({"key": 123.456}, {"key": "123.456"}),
        ({"key": []}, {"key": ""}),
        ({"key": [None]}, {"key": ""}),
        ({"key": [1, 2]}, {"key": "1,2"}),
        ({"key": [[1, 2], [3, 4]]}, {"key": "1,2 3,4"}),
    ],
    ids=[
        "empty-dict",
        "none-value",
        "string",
        "bytes",
        "float",
        "empty-list",
        "list-with-none",
        "flat-list",
        "nested-list",
    ],
)
def test_icat_serialize_fallback_valid_data(input_data, expected):
    assert fallback_serialization(input_data) == expected


def test_icat_serialize_fallback_datetime():
    now = datetime.datetime.now().astimezone()
    actual = fallback_serialization({"key": now})
    expected = {"key": datetime_utils.with_timezone_zulu_format(now)}
    assert actual == expected


@pytest.mark.parametrize(
    "invalid_value",
    [[{}], [[[1, 2], [3, 4]], [[5, 6], [7, 8]]], (7.3, "keV")],
    ids=["list-containing-dict", "3d-nested-list", "mixed-types"],
)
def test_icat_serialize_fallback_invalid_data(invalid_value):
    with pytest.raises(
        errors.IcatMetadataSerializationError, match="Invalid ICAT dataset parameter"
    ):
        fallback_serialization({"key": invalid_value})


def test_icat_serialize_fallback_boolean():
    actual = fallback_serialization({"key": True})
    expected = {"key": "true"}
    assert actual == expected

    actual = fallback_serialization({"key": False})
    expected = {"key": "false"}
    assert actual == expected
