from manifest_edit.plugin.mpd import ManifestIteratorPlugin
from manifest_edit.context import Context
from manifest_edit import libfmp4
from schema import Schema, Optional, Or
from manifest_edit.plugins.utility import renderFormatString


class Plugin(ManifestIteratorPlugin):
    """
    label add plugin.

    The purpose of this plugin is to add a label or a group label to a
    representation or an adaptation set.

    Users must provide at least the label text using the "data" field.
    As per standard "id" is optional and defaults to 0 and "lang" is optional.

    """

    _name = __name__

    _keys = ["label", "groupLabel", "force"]

    # This is just the specific ["how" config] for this plugin
    def schema(self):
        return Schema(
            {
                Optional(self._keys[0], default={}): Or({},{
                    Optional("id", default=0): int,
                    Optional("lang", default=""): str,
                    "data": str,
                }),
                Optional(self._keys[1], default={}): Or({},{
                    Optional("id", default=0): int,
                    Optional("lang", default=""): str,
                    "data": str,
                }),
                Optional(self._keys[2], default=False): bool,
            }
        )

    def _checkIfExists(self, attribute_name, label, element, force=False):

        if force == False and any(
            [
                existing_label == label
                for existing_label in getattr(element, attribute_name, [])
            ]
        ):
            return True

        return False

    def _addLabel(self, attribute_name, label, element, force=False):
        if not self._checkIfExists(attribute_name, label, element, force=force):
            try:
                getattr(element, attribute_name).append(label)
            except AttributeError:
                Context.log_error(
                    f"You cannot add {attribute_name} to an {type(element)}!"
                )

    def addLabelOrGroupLabel(self, manifest, storage):
        for label_config, element in self.config(manifest, storage):
            if (
                label_config["label"]
            ):
                self._addLabel(
                    attribute_name="labels",
                    label=libfmp4.mpd.Label(
                        label_config["label"]["id"],
                        renderFormatString(
                            element, label_config["label"]["lang"]
                        ),
                        renderFormatString(
                            element, label_config["label"]["data"]
                        ),
                    ),
                    element=element,
                    force=label_config["force"],
                )
            if (
                label_config["groupLabel"]
            ):
                self._addLabel(
                    attribute_name="groupLabels",
                    label=libfmp4.mpd.Label(
                        label_config["groupLabel"]["id"],
                        renderFormatString(
                            element, label_config["groupLabel"]["lang"]
                        ),
                        renderFormatString(
                            element, label_config["groupLabel"]["data"]
                        ),
                    ),
                    element=element,
                    force=label_config["force"],
                )

    def process(self, manifest, storage):
        self.addLabelOrGroupLabel(manifest, storage)
