import datetime
from numbers import Number
from typing import Any
from typing import Dict
from typing import Sequence

from .... import errors
from ...utils import datetime_utils


def fallback_serialization(
    parameters: Dict[str, Any],
) -> Dict[str, str]:
    """Naive parameter value serialization used when Pydantic validation fails and `strict=False`.

    :raises IcatMetadataSerializationError:
    """
    return {
        name: _serialize_parameter(name, value)
        for name, value in parameters.items()
        if value is not None
    }


def _serialize_parameter(name: str, value: Any, _depth: int = 0) -> str:
    if isinstance(value, str):
        return value
    elif isinstance(value, bytes):
        return value.decode()
    elif isinstance(value, bool):
        return "true" if value else "false"
    elif isinstance(value, Number):
        return str(value)
    elif isinstance(value, datetime.datetime):
        return datetime_utils.with_timezone_zulu_format(value)
    elif isinstance(value, Sequence):
        if _depth > 1:
            raise errors.IcatMetadataSerializationError(
                f"Invalid ICAT dataset parameter ({name}={value}): sequences can only be nested 2-levels deep"
            )

        if len({type(v) for v in value if v is not None}) > 1:
            raise errors.IcatMetadataSerializationError(
                f"Invalid ICAT dataset parameter ({name}={value}): sequences cannot have mixed types"
            )

        if all(isinstance(v, (str, bytes, Number)) or v is None for v in value):
            sep = ","
        else:
            sep = " "

        return sep.join(
            [
                _serialize_parameter(f"{name}[{i}]", v, _depth + 1)
                for i, v in enumerate(value)
                if v is not None
            ]
        )
    else:
        raise errors.IcatMetadataSerializationError(
            f"Invalid ICAT dataset parameter ({name}={value}): unsupported type {type(value)}"
        )
