"""Convert a dataclass to a jsonable dict.
A jsonable dict is a dict"""

from typing import Any
from enum import Enum
from dataclasses import is_dataclass, fields, MISSING
from .core import JsonableDict


def to_jdict(
    value: Any, ommit_default: bool = True, enum_to_string: bool = True
) -> JsonableDict:
    if not is_dataclass(value):
        raise TypeError(f'Value "{value}" is not a dataclass')

    data = {}
    for field in fields(value):
        value_ = getattr(value, field.name)
        if field.default is not MISSING and field.default == value_ and ommit_default:
            continue
        if (
            field.default_factory is not MISSING
            and value_ == field.default_factory()
            and ommit_default
        ):
            continue

        data[field.name] = _encode_value(value_, ommit_default, enum_to_string)
    return JsonableDict(**data)


def _encode_value(value: Any, ommit_default, enum_to_string):
    if is_dataclass(value) and not isinstance(value, type):
        data = to_jdict(value, ommit_default, enum_to_string)
        return data

    if isinstance(value, Enum):
        if enum_to_string:
            return value.name
        return value.value
    if isinstance(value, list):
        return [_encode_value(item, ommit_default, enum_to_string) for item in value]
    if isinstance(value, tuple):
        return tuple(
            [_encode_value(item, ommit_default, enum_to_string) for item in value]
        )
    if isinstance(value, dict):
        return {
            key: _encode_value(value_, ommit_default, enum_to_string)
            for key, value_ in value.items()
        }

    if type(value) in JsonableDict.PRIMITIVES:
        return value

    if value is None:
        return

    raise TypeError(f"Value {value} is not jsonable")
