# coding: utf-8

"""
DEX AI API

API for DEX AI

The version of the OpenAPI document: 2.0.0
Generated by OpenAPI Generator (https://openapi-generator.tech)

Do not edit the class manually.
"""  # noqa: E501

from __future__ import annotations
import pprint
import re  # noqa: F401
import json

from datetime import datetime
from pydantic import (
    BaseModel,
    ConfigDict,
    Field,
    StrictFloat,
    StrictInt,
    StrictStr,
    field_validator,
)
from typing import Any, ClassVar, Dict, List, Optional, Union
from crypticorn.dex.client.models.token_data import TokenData
from typing import Set
from typing_extensions import Self


class SignalWithToken(BaseModel):
    """
    Trading signal enriched with comprehensive token metadata and information.
    """  # noqa: E501

    stage: StrictStr = Field(description="Lifecycle stage")
    address: StrictStr = Field(description="Token contract address")
    pair_address: Optional[StrictStr] = None
    chain: StrictStr = Field(description="Chain")
    first_call_time: Optional[datetime] = None
    mc_at_call: Optional[StrictStr] = None
    ath_mc: Optional[StrictStr] = None
    last_x: Optional[StrictInt] = None
    call_id: Optional[StrictStr] = None
    called_at: datetime = Field(description="Time of the first call")
    updated_at: Optional[datetime] = None
    data: Optional[TokenData] = None
    performance: Optional[Union[StrictFloat, StrictInt]]
    __properties: ClassVar[List[str]] = [
        "stage",
        "address",
        "pair_address",
        "chain",
        "first_call_time",
        "mc_at_call",
        "ath_mc",
        "last_x",
        "call_id",
        "called_at",
        "updated_at",
        "data",
        "performance",
    ]

    @field_validator("chain")
    def chain_validate_enum(cls, value):
        """Validates the enum"""
        if value not in set(
            ["solana", "ethereum", "bsc", "base", "arbitrum", "polygon", "avalanche"]
        ):
            raise ValueError(
                "must be one of enum values ('solana', 'ethereum', 'bsc', 'base', 'arbitrum', 'polygon', 'avalanche')"
            )
        return value

    model_config = ConfigDict(
        populate_by_name=True,
        validate_assignment=True,
        protected_namespaces=(),
    )

    def to_str(self) -> str:
        """Returns the string representation of the model using alias"""
        return pprint.pformat(self.model_dump(by_alias=True))

    def to_json(self) -> str:
        """Returns the JSON representation of the model using alias"""
        # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
        return json.dumps(self.to_dict())

    @classmethod
    def from_json(cls, json_str: str) -> Optional[Self]:
        """Create an instance of SignalWithToken from a JSON string"""
        return cls.from_dict(json.loads(json_str))

    def to_dict(self) -> Dict[str, Any]:
        """Return the dictionary representation of the model using alias.

        This has the following differences from calling pydantic's
        `self.model_dump(by_alias=True)`:

        * `None` is only added to the output dict for nullable fields that
          were set at model initialization. Other fields with value `None`
          are ignored.
        """
        excluded_fields: Set[str] = set([])

        _dict = self.model_dump(
            by_alias=True,
            exclude=excluded_fields,
            exclude_none=True,
        )
        # override the default output from pydantic by calling `to_dict()` of data
        if self.data:
            _dict["data"] = self.data.to_dict()
        # set to None if pair_address (nullable) is None
        # and model_fields_set contains the field
        if self.pair_address is None and "pair_address" in self.model_fields_set:
            _dict["pair_address"] = None

        # set to None if first_call_time (nullable) is None
        # and model_fields_set contains the field
        if self.first_call_time is None and "first_call_time" in self.model_fields_set:
            _dict["first_call_time"] = None

        # set to None if mc_at_call (nullable) is None
        # and model_fields_set contains the field
        if self.mc_at_call is None and "mc_at_call" in self.model_fields_set:
            _dict["mc_at_call"] = None

        # set to None if ath_mc (nullable) is None
        # and model_fields_set contains the field
        if self.ath_mc is None and "ath_mc" in self.model_fields_set:
            _dict["ath_mc"] = None

        # set to None if last_x (nullable) is None
        # and model_fields_set contains the field
        if self.last_x is None and "last_x" in self.model_fields_set:
            _dict["last_x"] = None

        # set to None if call_id (nullable) is None
        # and model_fields_set contains the field
        if self.call_id is None and "call_id" in self.model_fields_set:
            _dict["call_id"] = None

        # set to None if updated_at (nullable) is None
        # and model_fields_set contains the field
        if self.updated_at is None and "updated_at" in self.model_fields_set:
            _dict["updated_at"] = None

        # set to None if data (nullable) is None
        # and model_fields_set contains the field
        if self.data is None and "data" in self.model_fields_set:
            _dict["data"] = None

        # set to None if performance (nullable) is None
        # and model_fields_set contains the field
        if self.performance is None and "performance" in self.model_fields_set:
            _dict["performance"] = None

        return _dict

    @classmethod
    def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
        """Create an instance of SignalWithToken from a dict"""
        if obj is None:
            return None

        if not isinstance(obj, dict):
            return cls.model_validate(obj)

        _obj = cls.model_validate(
            {
                "stage": obj.get("stage"),
                "address": obj.get("address"),
                "pair_address": obj.get("pair_address"),
                "chain": obj.get("chain"),
                "first_call_time": obj.get("first_call_time"),
                "mc_at_call": obj.get("mc_at_call"),
                "ath_mc": obj.get("ath_mc"),
                "last_x": obj.get("last_x"),
                "call_id": obj.get("call_id"),
                "called_at": obj.get("called_at"),
                "updated_at": obj.get("updated_at"),
                "data": TokenData.from_dict(obj["data"])
                if obj.get("data") is not None
                else None,
                "performance": obj.get("performance"),
            }
        )
        return _obj
