# fmt: off
# Generated by the protocol buffer compiler.  DO NOT EDIT!
from __future__ import annotations
from datetime import datetime, timedelta
import enum
from typing import Any, Dict, List, Optional, TypeVar, Type
from google.protobuf import timestamp_pb2
from google.protobuf import duration_pb2
from google.protobuf.json_format import MessageToDict

from continual.rpc.graphql import options_pb2


T = TypeVar("T")

def _to_proto_dict(x: dict) -> dict:
    """Converts dict to proto friendly representation."""
    out = dict()
    for key, item in x.items():
        if isinstance(item, list):
            out_list = []
            for e in item:
                if isinstance(e, datetime):
                    dt = timestamp_pb2.Timestamp()
                    dt.FromDatetime(e)
                    out_list.append(dt)
                elif isinstance(e, timedelta):
                    td = duration_pb2.Duration()
                    td.FromTimedelta(e)
                    out_list.append(td)
                elif hasattr(e, "to_proto"):
                    out_list.append(e.to_proto())
                else:
                    out_list.append(e)
            out[key] = out_list
        elif isinstance(item, datetime):
            dt = timestamp_pb2.Timestamp()
            dt.FromDatetime(item)
            out[key] = dt
        elif isinstance(item, timedelta):
            td = duration_pb2.Duration()
            td.FromTimedelta(item)
            out[key] = td
        elif hasattr(item, "to_proto"):
            out[key] = item.to_proto()
        else:
            out[key] = item
    return out


def _set_attribute(
    attributes: dict, class_name: str, field: str, value: Any, fieldType: Any, oneOfField: str
):
    """Helper that sets attribute on the object.
    
    Accepts dicts for classes and normalizes enums.
    """
    if isinstance(value, dict) and getattr(fieldType, "__origin__", None) == dict:
        attributes[field] = value
    elif isinstance(value, dict):
        attributes[field] = fieldType(**value)
    elif isinstance(value, list):
        innerType = fieldType.__args__[0]
        if innerType in [str, float, bool]:
            attributes[field] = value
        elif innerType is int:
            attributes[field] = [int(x) for x in value]
        elif issubclass(innerType, Enum):
            if len(value) > 0:
                if isinstance(value[0], str):
                    attributes[field] = [innerType(x.upper()) for x in value]
                elif isinstance(value[0], int) and getattr(innerType, "from_proto", None) is not None:
                    attributes[field] = [innerType.from_proto(x) for x in value]
        else:
            attributes[field] = [innerType(**x) for x in value]
    elif isinstance(value, str) and issubclass(fieldType, Enum):
        attributes[field] = fieldType(value.upper())
    elif isinstance(value, int) and issubclass(fieldType, Enum) and getattr(fieldType, "from_proto", None) is not None:
        attributes[field] = fieldType.from_proto(value)
    elif isinstance(value, str) and fieldType == datetime:
        dt = timestamp_pb2.Timestamp()
        dt.FromJsonString(value)
        attributes[field] = dt.ToDatetime()
    elif isinstance(value, str) and fieldType == timedelta:
        td = timestamp_pb2.Duration()
        td.FromJsonString(value)
        attributes[field] = td.ToTimeDelta()
    elif isinstance(value, str) and fieldType == int:
        # Needed to handle int64 encoded as strings.
        attributes[field] = int(value)
    # Set zero values to be consistent with proto.
    elif value is None:
        if fieldType == str:
            attributes[field] = ""
        elif fieldType == int:
            attributes[field] = 0
        elif fieldType == float:
            attributes[field] = 0.0
        elif fieldType == bool:
            attributes[field] = False
        elif getattr(fieldType, "__origin__", None) == list:
            attributes[field] = []
        elif getattr(fieldType, "__origin__", None) == dict:
            attributes[field] = {}
        elif fieldType == datetime or fieldType == timedelta:
            attributes[field] = None
        else:
            if oneOfField == "":
                attributes[field] = fieldType()
            else:
                attributes[field] = None
    elif value is not None and not isinstance(value, fieldType):
        raise ValueError(
            f"'{class_name}.{field}' must have type {fieldType}, got {type(value)}"
        )
    else:
        attributes[field] = value


class Enum(enum.Enum):
    """Base enum class.
    
    Overrides equality to be case insentitive.
    """

    def __eq__(self, other) -> bool:
        """Object is equal with all types."""
        if isinstance(other, str):
            return self.name == other.upper()
        elif isinstance(other, int):
            return self.value == other
        else:
            return self.value == other.value
    
    def __str__(self) -> str:
        return self.value


class GraphQLFieldOptions(Enum):
    """/ Designates a field within a message as being an input- or output-only type."""
    
    INPUT = "INPUT"
    OUTPUT = "OUTPUT"
    IGNORE = "IGNORE"

    @classmethod
    def from_proto(cls, value: int = 0) ->  GraphQLFieldOptions:
        """Convert enum from proto representation."""
        return cls(options_pb2.GraphQLFieldOptions.Name(value))

    def to_proto(self) -> int:
        """Convert enum to proto representation."""
        return options_pb2.GraphQLFieldOptions.Value(self.value)
