from __future__ import annotations

from typing import Any, AnyStr, Dict, Union

import openvds

from ovds_utils.exceptions import VDSMetadataException
from ovds_utils.ovds import METADATATYPE_TO_OVDS_GET_FUNCTION, METADATATYPE_TO_OVDS_SET_FUNCTION, MetadataTypes


class MetadataValue:
    def __init__(self, value: Any, category: AnyStr, type: Union[AnyStr, MetadataTypes]) -> None:
        self.value = value
        self.category = category
        if isinstance(type, MetadataTypes):
            self._type = type
        elif str(type) not in METADATATYPE_TO_OVDS_GET_FUNCTION:
            raise VDSMetadataException(
                f"The type {type} was not recognized among: {', '.join(METADATATYPE_TO_OVDS_GET_FUNCTION.keys())}")
        else:
            self._type = getattr(MetadataTypes, str(type).replace("MetadataType.", ""))

    def __repr__(self) -> str:
        return f"<{self.__class__.__qualname__}(value={self.value}, category={self.category}, type={self.type})>"

    @property
    def type(self):
        return self._type.value


class MetadataContainer(dict):
    def __init__(self, **kwargs: Dict[AnyStr, MetadataValue]) -> None:
        super().__init__()
        self.update(kwargs)

    def __repr__(self) -> str:
        return f"<{self.__class__.__qualname__}({', '.join(self.keys())})>"

    def get_container(self):
        container = openvds.MetadataContainer()
        for k, v in self.items():
            set_method = METADATATYPE_TO_OVDS_SET_FUNCTION[v.type]
            set_method(container, v.category, k, v.value)
        return container

    @staticmethod
    def get_from_layout(layout: openvds.core.VolumeDataLayout) -> openvds.core.MetadataContainer:
        metadata = {}
        for i in layout.getMetadataKeys():
            method = METADATATYPE_TO_OVDS_GET_FUNCTION[str(i.type)]
            value = method(layout, i.category, i.name)
            metadata[i.name] = MetadataValue(value, i.category, i.type)

        return MetadataContainer(**metadata)
