"""
Snowflake Procedure API.

The Snowflake Procedure API is a REST API that you can use to access, update, and perform certain actions on Procedure resource in a Snowflake database.  # noqa: E501

The version of the OpenAPI document: 0.0.1
Contact: support@snowflake.com
Generated by: https://openapi-generator.tech

Do not edit this file manually.
"""

from __future__ import annotations

import json
import pprint
import re

from datetime import datetime
from typing import Any, List, Optional

from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr, field_validator
from typing_extensions import Annotated

from snowflake.core.procedure._generated.models.argument import Argument, ArgumentModel
from snowflake.core.procedure._generated.models.function_language import FunctionLanguage, FunctionLanguageModel
from snowflake.core.procedure._generated.models.return_type import ReturnType, ReturnTypeModel


class Procedure(BaseModel):
    """A model object representing the Procedure resource.

    Constructs an object of type Procedure with the provided properties.

    Parameters
    __________
    name : str
        Name of the procedure
    arguments : list[Argument]
        List of arguments for the function/procedure
    return_type : ReturnType

    language_config : FunctionLanguage

    execute_as : str, optional
        What permissions should the procedure execution be called with
    is_secure : bool, optional
        Specifies whether the function/procedure is secure or not
    comment : str, optional
        Specifies a comment for the function/procedure
    body : str, optional
        Function/procedure definition
    created_on : datetime, optional
        The date and time when the function/procedure was created — **Read-only:** *any user-provided value will be ignored.*
    schema_name : str, optional
        The name of the schema in which the function/procedure exists — **Read-only:** *any user-provided value will be ignored.*
    database_name : str, optional
        The name of the database in which the function/procedure exists — **Read-only:** *any user-provided value will be ignored.*
    min_num_arguments : int, optional
        The minimum number of arguments — **Read-only:** *any user-provided value will be ignored.*
    max_num_arguments : int, optional
        The maximum number of arguments — **Read-only:** *any user-provided value will be ignored.*
    owner : str, optional
        Role that owns the function/procedure — **Read-only:** *any user-provided value will be ignored.*
    owner_role_type : str, optional
        The type of role that owns the function/procedure — **Read-only:** *any user-provided value will be ignored.*
    is_builtin : bool, optional
        If the function/procedure is built-in or not (user-defined) — **Read-only:** *any user-provided value will be ignored.*
    """

    name: Annotated[str, Field(strict=True)]

    execute_as: Optional[StrictStr] = None

    is_secure: Optional[StrictBool] = None

    arguments: List[Argument]

    return_type: ReturnType

    language_config: FunctionLanguage

    comment: Optional[StrictStr] = None

    body: Optional[StrictStr] = None

    created_on: Optional[datetime] = None

    schema_name: Optional[Annotated[str, Field(strict=True)]] = None

    database_name: Optional[Annotated[str, Field(strict=True)]] = None

    min_num_arguments: Optional[StrictInt] = None

    max_num_arguments: Optional[StrictInt] = None

    owner: Optional[StrictStr] = None

    owner_role_type: Optional[StrictStr] = None

    is_builtin: Optional[StrictBool] = None

    __properties = [
        "name",
        "execute_as",
        "is_secure",
        "arguments",
        "return_type",
        "language_config",
        "comment",
        "body",
        "created_on",
        "schema_name",
        "database_name",
        "min_num_arguments",
        "max_num_arguments",
        "owner",
        "owner_role_type",
        "is_builtin",
    ]

    @field_validator("name")
    def name_validate_regular_expression(cls, v):
        if not re.match(r"""^\"([^\"]|\"\")+\"|[a-zA-Z_][a-zA-Z0-9_$]*$""", v):
            raise ValueError(r"""must validate the regular expression /^"([^"]|"")+"|[a-zA-Z_][a-zA-Z0-9_$]*$/""")
        return v

    @field_validator("execute_as")
    def execute_as_validate_enum(cls, v):
        if v is None:
            return v
        if v not in ("CALLER", "OWNER"):
            raise ValueError("must validate the enum values ('CALLER','OWNER')")
        return v

    @field_validator("schema_name")
    def schema_name_validate_regular_expression(cls, v):
        if v is None:
            return v
        if not re.match(r"""^\"([^\"]|\"\")+\"|[a-zA-Z_][a-zA-Z0-9_$]*$""", v):
            raise ValueError(r"""must validate the regular expression /^"([^"]|"")+"|[a-zA-Z_][a-zA-Z0-9_$]*$/""")
        return v

    @field_validator("database_name")
    def database_name_validate_regular_expression(cls, v):
        if v is None:
            return v
        if not re.match(r"""^\"([^\"]|\"\")+\"|[a-zA-Z_][a-zA-Z0-9_$]*$""", v):
            raise ValueError(r"""must validate the regular expression /^"([^"]|"")+"|[a-zA-Z_][a-zA-Z0-9_$]*$/""")
        return v

    model_config = ConfigDict(
        validate_by_name=True,
        validate_assignment=True,
    )

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

    def to_json(self) -> str:
        """Returns the JSON representation of the model using alias."""
        return json.dumps(self.to_dict())

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

    def to_dict(
        self,
        hide_readonly_properties: bool = False,
    ) -> dict[str, Any]:
        """Returns the dictionary representation of the model using alias."""
        exclude_properties = set()

        if hide_readonly_properties:
            exclude_properties.update(
                {
                    "created_on",
                    "schema_name",
                    "database_name",
                    "min_num_arguments",
                    "max_num_arguments",
                    "owner",
                    "owner_role_type",
                    "is_builtin",
                }
            )

        _dict = self.model_dump(serialize_as_any=True, by_alias=True, exclude=exclude_properties, exclude_none=True)

        # override the default output from pydantic by calling `to_dict()` of each item in arguments (list)
        _items = []
        if self.arguments:
            for _item in self.arguments:
                if _item:
                    _items.append(_item.to_dict())
            _dict["arguments"] = _items

        # override the default output from pydantic by calling `to_dict()` of return_type
        if self.return_type:
            _dict["return_type"] = self.return_type.to_dict()

        # override the default output from pydantic by calling `to_dict()` of language_config
        if self.language_config:
            _dict["language_config"] = self.language_config.to_dict()

        return _dict

    def to_dict_without_readonly_properties(self) -> dict[str, Any]:
        """Return the dictionary representation of the model without readonly properties."""
        return self.to_dict(hide_readonly_properties=True)

    @classmethod
    def from_dict(cls, obj: dict) -> Procedure:
        """Create an instance of Procedure from a dict."""
        if obj is None:
            return None

        if type(obj) is not dict:
            return Procedure.model_validate(obj)

        _obj = Procedure.model_validate(
            {
                "name": obj.get("name"),
                "execute_as": obj.get("execute_as"),
                "is_secure": obj.get("is_secure"),
                "arguments": [Argument.from_dict(_item) for _item in obj.get("arguments")]
                if obj.get("arguments") is not None
                else None,
                "return_type": ReturnType.from_dict(obj.get("return_type"))
                if obj.get("return_type") is not None
                else None,
                "language_config": FunctionLanguage.from_dict(obj.get("language_config"))
                if obj.get("language_config") is not None
                else None,
                "comment": obj.get("comment"),
                "body": obj.get("body"),
                "created_on": obj.get("created_on"),
                "schema_name": obj.get("schema_name"),
                "database_name": obj.get("database_name"),
                "min_num_arguments": obj.get("min_num_arguments"),
                "max_num_arguments": obj.get("max_num_arguments"),
                "owner": obj.get("owner"),
                "owner_role_type": obj.get("owner_role_type"),
                "is_builtin": obj.get("is_builtin"),
            }
        )

        return _obj


class ProcedureModel:
    def __init__(
        self,
        name: str,
        arguments: list[Argument],
        return_type: ReturnType,
        language_config: FunctionLanguage,
        # optional properties
        execute_as: Optional[str] = None,
        is_secure: Optional[bool] = None,
        comment: Optional[str] = None,
        body: Optional[str] = None,
        created_on: Optional[datetime] = None,
        schema_name: Optional[str] = None,
        database_name: Optional[str] = None,
        min_num_arguments: Optional[int] = None,
        max_num_arguments: Optional[int] = None,
        owner: Optional[str] = None,
        owner_role_type: Optional[str] = None,
        is_builtin: Optional[bool] = None,
    ):
        """A model object representing the Procedure resource.

        Constructs an object of type Procedure with the provided properties.

        Parameters
        __________
        name : str
            Name of the procedure
        arguments : list[Argument]
            List of arguments for the function/procedure
        return_type : ReturnType

        language_config : FunctionLanguage

        execute_as : str, optional
            What permissions should the procedure execution be called with
        is_secure : bool, optional
            Specifies whether the function/procedure is secure or not
        comment : str, optional
            Specifies a comment for the function/procedure
        body : str, optional
            Function/procedure definition
        created_on : datetime, optional
            The date and time when the function/procedure was created
        schema_name : str, optional
            The name of the schema in which the function/procedure exists.
        database_name : str, optional
            The name of the database in which the function/procedure exists.
        min_num_arguments : int, optional
            The minimum number of arguments
        max_num_arguments : int, optional
            The maximum number of arguments
        owner : str, optional
            Role that owns the function/procedure
        owner_role_type : str, optional
            The type of role that owns the function/procedure
        is_builtin : bool, optional
            If the function/procedure is built-in or not (user-defined)
        """
        self.name = name
        self.execute_as = execute_as
        self.is_secure = is_secure
        self.arguments = arguments
        self.return_type = return_type
        self.language_config = language_config
        self.comment = comment
        self.body = body
        self.created_on = created_on
        self.schema_name = schema_name
        self.database_name = database_name
        self.min_num_arguments = min_num_arguments
        self.max_num_arguments = max_num_arguments
        self.owner = owner
        self.owner_role_type = owner_role_type
        self.is_builtin = is_builtin

    __properties = [
        "name",
        "execute_as",
        "is_secure",
        "arguments",
        "return_type",
        "language_config",
        "comment",
        "body",
        "created_on",
        "schema_name",
        "database_name",
        "min_num_arguments",
        "max_num_arguments",
        "owner",
        "owner_role_type",
        "is_builtin",
    ]

    def __repr__(self) -> str:
        return repr(self._to_model())

    def _to_model(self):
        return Procedure(
            name=self.name,
            execute_as=self.execute_as,
            is_secure=self.is_secure,
            arguments=[x._to_model() for x in self.arguments] if self.arguments is not None else None,
            return_type=self.return_type._to_model() if self.return_type is not None else None,
            language_config=self.language_config._to_model() if self.language_config is not None else None,
            comment=self.comment,
            body=self.body,
            created_on=self.created_on,
            schema_name=self.schema_name,
            database_name=self.database_name,
            min_num_arguments=self.min_num_arguments,
            max_num_arguments=self.max_num_arguments,
            owner=self.owner,
            owner_role_type=self.owner_role_type,
            is_builtin=self.is_builtin,
        )

    @classmethod
    def _from_model(cls, model) -> ProcedureModel:
        return ProcedureModel(
            name=model.name,
            execute_as=model.execute_as,
            is_secure=model.is_secure,
            arguments=[ArgumentModel._from_model(x) for x in model.arguments] if model.arguments else None,
            return_type=ReturnTypeModel._from_model(model.return_type) if model.return_type else None,
            language_config=FunctionLanguageModel._from_model(model.language_config) if model.language_config else None,
            comment=model.comment,
            body=model.body,
            created_on=model.created_on,
            schema_name=model.schema_name,
            database_name=model.database_name,
            min_num_arguments=model.min_num_arguments,
            max_num_arguments=model.max_num_arguments,
            owner=model.owner,
            owner_role_type=model.owner_role_type,
            is_builtin=model.is_builtin,
        )

    def to_dict(self):
        """Create a dictionary of the properties from a Procedure.

        This method constructs a dictionary with the key-value entries corresponding to the properties of the Procedure object.

        Returns
        _______
        dict
            A dictionary object created using the input model.
        """
        return self._to_model().to_dict()

    @classmethod
    def from_dict(cls, obj: dict) -> ProcedureModel:
        """Create an instance of Procedure from a dict.

        This method constructs a Procedure object from a dictionary with the key-value pairs of its properties.

        Parameters
        ----------
        obj : dict
            A dictionary whose keys and values correspond to the properties of the resource object.

        Returns
        _______
        Procedure
            A Procedure object created using the input dictionary; this will fail if the required properties are missing.
        """
        return cls._from_model(Procedure.from_dict(obj))


Procedure._model_class = ProcedureModel
