# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/02_datatypes.ipynb.

# %% auto 0
__all__ = [
    "AtomicField",
    "SimpleField",
    "EncodedString",
    "FieldWithOptions",
    "Coordenadas",
    "GerarPlai",
]

# %% ../nbs/02_datatypes.ipynb 2
from dataclasses import dataclass
from itertools import product
from functools import cached_property

from fastcore.xtras import listify


# %% ../nbs/02_datatypes.ipynb 3
@dataclass
class AtomicField:
    name: str
    keyword: str
    mandatory: bool = True

    @classmethod
    def reset(cls, instance):
        new_instance = cls(
            **{k: v for k, v in instance.__dict__.items() if k != "value"}
        )
        return new_instance

    @property
    def dtype(self):
        return "string"

    @cached_property
    def value(self):
        return ""

    def __call__(self, value):
        self.value = value
        return value

    def __repr__(self) -> str:
        string = ""
        if hasattr(self, "value"):
            string = f"(value: {self.value})"
        if self.mandatory:
            string += " | <mandatory>"
        return string


# %% ../nbs/02_datatypes.ipynb 4
@dataclass
class SimpleField:
    id: int
    name: str
    mandatory: bool = False
    multiple: bool = False
    format_value: bool = False
    _dtype: str = "string"

    @classmethod
    def reset(cls, instance):
        new_instance = cls(
            **{k: v for k, v in instance.__dict__.items() if k != "value"}
        )
        return new_instance

    @property
    def dtype(self):
        return self._dtype

    @dtype.setter
    def dtype(self, value):
        self._dtype = value

    @cached_property
    def value(self):
        match self.dtype:
            case "string":
                return ""
            case "int":
                return 0
            case "float":
                return 0.0
            case "list":
                return []
            case _:
                return None

    def format_value_string(self, value: str) -> str:
        if self.format_value:
            return "{" + '"valor":"{0}","texto":"{0}"'.format(value) + "}"
        try:
            value = str(value)
        except TypeError as e:
            raise ValueError(
                f"The value: {value} cannot be converted to a string"
            ) from e

        return value

    def validate_value(self, value: str | list) -> str | list:
        if self.multiple:
            return [self.format_value_string(v) for v in listify(value)]
        else:
            return self.format_value_string(value)

    def __call__(self, value: str | list) -> dict[str, str | list]:
        self.value = value
        return {"id": self.id, "value": self.validate_value(value)}

    def __repr__(self) -> str:
        string = f'(value: {getattr(self, "value", "")})'
        if self.mandatory:
            string += " | <mandatory>"
        if self.multiple:
            string += ", <multiple>"
        return string


# %% ../nbs/02_datatypes.ipynb 5
@dataclass
class EncodedString(SimpleField):
    """This class always format the value string
    The json key is called 'numero'
    """

    def format_value_string(self, value: str) -> str:
        return "{" + '"numero"=>"{0}"'.format(value) + "}"

    def __repr__(self) -> str:
        return super().__repr__()


# %% ../nbs/02_datatypes.ipynb 6
@dataclass
class FieldWithOptions(SimpleField):
    options: list[str] = None
    mapping: dict[str, list] = None

    @property
    def dtype(self):
        if self.multiple:
            self._dtype = "list"
        return self._dtype

    def __call__(self, value: str | list) -> dict[str, str | list]:
        if self.multiple:
            value = [str(v) for v in listify(value)]
            for v in value:
                if self.options and v not in self.options:
                    raise ValueError(
                        f"The value {v} must be one of the valid options: {self.options} for field {self.name}"
                    )
            if isinstance(self.options, dict):
                value = [self.options[v] for v in value]
        else:
            value = str(value)
            if self.options and value not in self.options:
                raise ValueError(
                    f"The value {value} must be one of the valid options: {self.options} for field {self.name}"
                )
            if isinstance(self.options, dict):
                value = self.options[value]
        self.value = value
        return {"id": self.id, "value": self.validate_value(value)}

    def __repr__(self) -> str:
        string = ""
        if hasattr(self, "value"):
            string = f"(value: {self.value})"
        if self.mandatory:
            string += " | <mandatory>"
        if self.multiple:
            string += ", <multiple>"
        if self.options:
            string += ", <options>"
        if self.mapping is not None:
            string += ", conditional"
        return string


# %% ../nbs/02_datatypes.ipynb 7
@dataclass
class Coordenadas:
    id: int
    name: str
    mandatory: bool = False

    @classmethod
    def reset(cls, instance):
        new_instance = cls(
            **{k: v for k, v in instance.__dict__.items() if k != "value"}
        )
        return new_instance

    @cached_property
    def value(self):
        return None

    def format_value_string(self, latitude: str, longitude: str) -> str:
        return (
            "{"
            + '"latitude"=>"{0}","longitude"=>"{1}"'.format(latitude, longitude)
            + "}"
        )

    def __call__(self, coords) -> dict[str, str]:
        latitude, longitude = coords[0], coords[1]
        self.value = (latitude, longitude)
        return {
            "id": self.id,
            "value": self.format_value_string(latitude, longitude),
        }

    def __repr__(self) -> str:
        string = ""
        if hasattr(self, "value"):
            string = f"(value: {self.value})"
        if self.mandatory:
            string += " | <mandatory>"
        return string


# %% ../nbs/02_datatypes.ipynb 8
@dataclass
class GerarPlai:
    id: int
    name: str
    mandatory: bool = False
    TIPO_DE_PROCESSO = [
        "Gestão da Fiscalização: Lacração, Apreensão e Interrupção",
        "Gestão da Fiscalização: Processo de Guarda",
    ]
    COORD_FI = ["FI", "FI1", "FI2", "FI3"]
    CODES = ["100000539", "100000618"]
    options = list(product(TIPO_DE_PROCESSO, COORD_FI))

    @classmethod
    def reset(cls, instance):
        new_instance = cls(
            **{k: v for k, v in instance.__dict__.items() if k != "value"}
        )
        return new_instance

    @cached_property
    def value(self):
        return "0"

    def validate_tipo_processo(self, value: str) -> str:
        options = dict(zip(self.TIPO_DE_PROCESSO, self.CODES))
        if value not in options:
            raise ValueError("tipo de processo PLAI é inválido")
        return options[value]

    def validate_coord_fi(self, value: str) -> str:
        if value not in self.COORD_FI:
            raise ValueError("coord_fi is invalid")
        return value

    def validate_values(self, tipo_processo: str = "", coord_fi: str = "") -> str:
        tipo_processo = self.validate_tipo_processo(tipo_processo)
        coord_fi = self.validate_coord_fi(coord_fi)
        self.value = (tipo_processo, coord_fi)
        return (
            "{"
            + '"criar_processo"=>"1","tipo_processo"=>"{0}","coord_fi"=>"{1}"'.format(
                tipo_processo, coord_fi
            )
            + "}"
        )

    def __call__(self, args: tuple) -> dict[str, str]:
        if len(args) == 2:
            tipo_processo, coord_fi = args
        else:
            raise ValueError("tipo_de_processo_plai and coord_fi_plai are required")

        value = self.validate_values(tipo_processo, coord_fi)
        return {"id": self.id, "value": value}

    def __repr__(self) -> str:
        string = ""
        if hasattr(self, "value"):
            string = f"(value: {self.value})"
        if self.mandatory:
            string += " | <mandatory>"
        return string
