from typing import Optional, Union, Dict
from uuid import UUID

from datalogue.errors import DtlError
from datalogue.dtl_utils import map_option, _parse_uuid


class PipelineTemplate:
    """
    A local pipeline template. Once created, this template can be
    passed mapped inputs to generate pipelines or jobs

    :param name: a name for this template
    :param template: the structure of the template, as a YAML-styled
    string. Please see https://mustache.github.io/mustache.5.html
    :param dummy_input_map: an example of data that will be used to
    validate this template upon creation, unless disabled upon the
    creation step
    :param :id: will be generated by the backend upon creation and used to
    reference this template
    """

    def __init__(
        self, name: str, template: str, dummy_input_map: Optional[Dict[str, str]] = None, id: Optional[UUID] = None,
    ):
        self.name = name
        self.template = template
        self.dummy_input_map = dummy_input_map
        self.id = id

    def __eq__(self, other):
        return (self.name == other.name) and (self.id == other.id)

    def __repr__(self):
        return (
            f"{self.__class__.__name__}(\n"
            f"id= {self.id!r},\n"
            f"name= {self.name!r},\n"
            f"template= {self.template}\n"
            f")"
        )

    def _as_payload(self) -> Union[DtlError, dict]:
        payload = {
            "name": self.name,
            "template": self.template,
            "dummy_input_map": self.dummy_input_map,
        }
        return payload

    @staticmethod
    def _from_payload(payload: dict) -> Union[DtlError, "PipelineTemplate"]:
        name = payload.get("name")
        if name is None:
            return DtlError("'name' is missing for a template")

        id = map_option(payload.get("id"), _parse_uuid)
        template = payload.get("template")
        # todo anmol - put the below fields in return instance as well
        created_by = payload.get("createdBy")
        created_at = payload.get("createdAt")
        updated_at = payload.get("updatedAt")
        last_update_by = map_option(payload.get("lastUpdateBy"), _parse_uuid)

        return PipelineTemplate(name, template, id=id)
