"""
Snowflake Stage API.

The Snowflake Stage API is a REST API that you can use to access, update, and perform certain actions on stage resources 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, Optional

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

from snowflake.core.stage._generated.models.credentials import Credentials, CredentialsModel
from snowflake.core.stage._generated.models.stage_directory_table import StageDirectoryTable, StageDirectoryTableModel
from snowflake.core.stage._generated.models.stage_encryption import StageEncryption, StageEncryptionModel


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

    Constructs an object of type Stage with the provided properties.

    Parameters
    __________
    name : str
        A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive.
    kind : str,  default 'PERMANENT'
        Specifies whether the stage is permanent or temporary.
    url : str, optional
        URL for the external stage; blank for an internal stage.
    endpoint : str, optional
        The S3-compatible API endpoint associated with the stage; always NULL for stages that are not S3-compatible.
    storage_integration : str, optional
        A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive.
    comment : str, optional
        Specifies a comment for the stage.
    credentials : Credentials, optional

    encryption : StageEncryption, optional

    directory_table : StageDirectoryTable, optional

    created_on : datetime, optional
        Date and time when the stage was created — **Read-only:** *any user-provided value will be ignored.*
    has_credentials : bool, optional
        Indicates that the external stage has access credentials; always false for an internal stage — **Read-only:** *any user-provided value will be ignored.*
    has_encryption_key : bool, optional
        Indicates that the external stage contains encrypted files; always false for an internal stage — **Read-only:** *any user-provided value will be ignored.*
    owner : str, optional
        Role that owns the stage — **Read-only:** *any user-provided value will be ignored.*
    owner_role_type : str, optional
        The type of role that owns the object, either ROLE or DATABASE_ROLE. If a Snowflake Native App owns the object, the value is APPLICATION. Snowflake returns NULL if you delete the object because a deleted object does not have an owner role — **Read-only:** *any user-provided value will be ignored.*
    region : str, optional
        Region where the stage is located — **Read-only:** *any user-provided value will be ignored.*
    cloud : str, optional
        Cloud provider; always NULL for an internal stage — **Read-only:** *any user-provided value will be ignored.*
    """

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

    kind: Optional[StrictStr] = "PERMANENT"

    url: Optional[StrictStr] = None

    endpoint: Optional[StrictStr] = None

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

    comment: Optional[StrictStr] = None

    credentials: Optional[Credentials] = None

    encryption: Optional[StageEncryption] = None

    directory_table: Optional[StageDirectoryTable] = None

    created_on: Optional[datetime] = None

    has_credentials: Optional[StrictBool] = None

    has_encryption_key: Optional[StrictBool] = None

    owner: Optional[StrictStr] = None

    owner_role_type: Optional[StrictStr] = None

    region: Optional[StrictStr] = None

    cloud: Optional[StrictStr] = None

    __properties = [
        "name",
        "kind",
        "url",
        "endpoint",
        "storage_integration",
        "comment",
        "credentials",
        "encryption",
        "directory_table",
        "created_on",
        "has_credentials",
        "has_encryption_key",
        "owner",
        "owner_role_type",
        "region",
        "cloud",
    ]

    @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("kind")
    def kind_validate_enum(cls, v):
        if v is None:
            return v
        if v not in ("PERMANENT", "TEMPORARY"):
            raise ValueError("must validate the enum values ('PERMANENT','TEMPORARY')")
        return v

    @field_validator("storage_integration")
    def storage_integration_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) -> Stage:
        """Create an instance of Stage 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",
                    "has_credentials",
                    "has_encryption_key",
                    "owner",
                    "owner_role_type",
                    "region",
                    "cloud",
                }
            )

        _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 credentials
        if self.credentials:
            _dict["credentials"] = self.credentials.to_dict()

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

        # override the default output from pydantic by calling `to_dict()` of directory_table
        if self.directory_table:
            _dict["directory_table"] = self.directory_table.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) -> Stage:
        """Create an instance of Stage from a dict."""
        if obj is None:
            return None

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

        _obj = Stage.model_validate(
            {
                "name": obj.get("name"),
                "kind": obj.get("kind") if obj.get("kind") is not None else "PERMANENT",
                "url": obj.get("url"),
                "endpoint": obj.get("endpoint"),
                "storage_integration": obj.get("storage_integration"),
                "comment": obj.get("comment"),
                "credentials": Credentials.from_dict(obj.get("credentials"))
                if obj.get("credentials") is not None
                else None,
                "encryption": StageEncryption.from_dict(obj.get("encryption"))
                if obj.get("encryption") is not None
                else None,
                "directory_table": StageDirectoryTable.from_dict(obj.get("directory_table"))
                if obj.get("directory_table") is not None
                else None,
                "created_on": obj.get("created_on"),
                "has_credentials": obj.get("has_credentials"),
                "has_encryption_key": obj.get("has_encryption_key"),
                "owner": obj.get("owner"),
                "owner_role_type": obj.get("owner_role_type"),
                "region": obj.get("region"),
                "cloud": obj.get("cloud"),
            }
        )

        return _obj


class StageModel:
    def __init__(
        self,
        name: str,
        # optional properties
        kind: Optional[str] = "PERMANENT",
        url: Optional[str] = None,
        endpoint: Optional[str] = None,
        storage_integration: Optional[str] = None,
        comment: Optional[str] = None,
        credentials: Optional[Credentials] = None,
        encryption: Optional[StageEncryption] = None,
        directory_table: Optional[StageDirectoryTable] = None,
        created_on: Optional[datetime] = None,
        has_credentials: Optional[bool] = None,
        has_encryption_key: Optional[bool] = None,
        owner: Optional[str] = None,
        owner_role_type: Optional[str] = None,
        region: Optional[str] = None,
        cloud: Optional[str] = None,
    ):
        """A model object representing the Stage resource.

        Constructs an object of type Stage with the provided properties.

        Parameters
        __________
        name : str
            A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive.
        kind : str,  default 'PERMANENT'
            Specifies whether the stage is permanent or temporary.
        url : str, optional
            URL for the external stage; blank for an internal stage.
        endpoint : str, optional
            The S3-compatible API endpoint associated with the stage; always NULL for stages that are not S3-compatible.
        storage_integration : str, optional
            A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive.
        comment : str, optional
            Specifies a comment for the stage.
        credentials : Credentials, optional

        encryption : StageEncryption, optional

        directory_table : StageDirectoryTable, optional

        created_on : datetime, optional
            Date and time when the stage was created.
        has_credentials : bool, optional
            Indicates that the external stage has access credentials; always false for an internal stage.
        has_encryption_key : bool, optional
            Indicates that the external stage contains encrypted files; always false for an internal stage.
        owner : str, optional
            Role that owns the stage.
        owner_role_type : str, optional
            The type of role that owns the object, either ROLE or DATABASE_ROLE. If a Snowflake Native App owns the object, the value is APPLICATION. Snowflake returns NULL if you delete the object because a deleted object does not have an owner role.
        region : str, optional
            Region where the stage is located.
        cloud : str, optional
            Cloud provider; always NULL for an internal stage.
        """
        self.name = name
        self.kind = kind
        self.url = url
        self.endpoint = endpoint
        self.storage_integration = storage_integration
        self.comment = comment
        self.credentials = credentials
        self.encryption = encryption
        self.directory_table = directory_table
        self.created_on = created_on
        self.has_credentials = has_credentials
        self.has_encryption_key = has_encryption_key
        self.owner = owner
        self.owner_role_type = owner_role_type
        self.region = region
        self.cloud = cloud

    __properties = [
        "name",
        "kind",
        "url",
        "endpoint",
        "storage_integration",
        "comment",
        "credentials",
        "encryption",
        "directory_table",
        "created_on",
        "has_credentials",
        "has_encryption_key",
        "owner",
        "owner_role_type",
        "region",
        "cloud",
    ]

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

    def _to_model(self):
        return Stage(
            name=self.name,
            kind=self.kind,
            url=self.url,
            endpoint=self.endpoint,
            storage_integration=self.storage_integration,
            comment=self.comment,
            credentials=self.credentials._to_model() if self.credentials is not None else None,
            encryption=self.encryption._to_model() if self.encryption is not None else None,
            directory_table=self.directory_table._to_model() if self.directory_table is not None else None,
            created_on=self.created_on,
            has_credentials=self.has_credentials,
            has_encryption_key=self.has_encryption_key,
            owner=self.owner,
            owner_role_type=self.owner_role_type,
            region=self.region,
            cloud=self.cloud,
        )

    @classmethod
    def _from_model(cls, model) -> StageModel:
        return StageModel(
            name=model.name,
            kind=model.kind,
            url=model.url,
            endpoint=model.endpoint,
            storage_integration=model.storage_integration,
            comment=model.comment,
            credentials=CredentialsModel._from_model(model.credentials) if model.credentials else None,
            encryption=StageEncryptionModel._from_model(model.encryption) if model.encryption else None,
            directory_table=StageDirectoryTableModel._from_model(model.directory_table)
            if model.directory_table
            else None,
            created_on=model.created_on,
            has_credentials=model.has_credentials,
            has_encryption_key=model.has_encryption_key,
            owner=model.owner,
            owner_role_type=model.owner_role_type,
            region=model.region,
            cloud=model.cloud,
        )

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

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

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

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

        This method constructs a Stage 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
        _______
        Stage
            A Stage object created using the input dictionary; this will fail if the required properties are missing.
        """
        return cls._from_model(Stage.from_dict(obj))


Stage._model_class = StageModel
