"""
TODO:
 - ensure import order or at least warn or smth lol
 - raise exception on ambiguous 'registered' impls
"""
import collections.abc
import typing as ta

from .. import check
from .. import dataclasses as dc
from .. import lang
from .. import marshal as msh
from .. import reflect as rfl
from .secrets import Secret
from .secrets import SecretRef
from .secrets import SecretRefOrStr


##


class StrOrSecretRefMarshalerUnmarshaler(msh.Marshaler, msh.Unmarshaler):
    def marshal(self, ctx: msh.MarshalContext, o: ta.Any) -> msh.Value:
        if isinstance(o, str):
            return o
        elif isinstance(o, SecretRef):
            return {'secret': o.key}
        else:
            raise TypeError(o)

    def unmarshal(self, ctx: msh.UnmarshalContext, v: msh.Value) -> ta.Any:
        if isinstance(v, str):
            return v
        elif isinstance(v, collections.abc.Mapping):
            [(mk, mv)] = v.items()
            if mk != 'secret':
                raise TypeError(v)
            return SecretRef(check.isinstance(mv, str))
        else:
            raise TypeError(v)


@dc.field_modifier
def marshal_secret_field(f: dc.Field) -> dc.Field:
    """Mostly obsolete with auto-registration below."""

    return dc.set_field_metadata(f, {
        msh.FieldOptions: dc.replace(
            f.metadata.get(msh.FieldOptions, msh.FieldOptions()),
            marshaler=StrOrSecretRefMarshalerUnmarshaler(),
            unmarshaler=StrOrSecretRefMarshalerUnmarshaler(),
        ),
    })


@lang.static_init
def _install_standard_marshaling() -> None:
    msh.install_standard_factories(
        msh.ForbiddenTypeMarshalerFactory({Secret}),
        msh.ForbiddenTypeUnmarshalerFactory({Secret}),

        msh.TypeMapMarshalerFactory({
            rfl.type_(SecretRefOrStr): StrOrSecretRefMarshalerUnmarshaler(),
        }),
        msh.TypeMapUnmarshalerFactory({
            rfl.type_(SecretRefOrStr): StrOrSecretRefMarshalerUnmarshaler(),
        }),
    )
