"""
Snowflake Iceberg Table API.

The Snowflake Iceberg Table API is a REST API that you can use to access, update, and perform certain actions on Iceberg Table 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.iceberg_table._generated.models.constraint import Constraint, ConstraintModel
from snowflake.core.iceberg_table._generated.models.iceberg_table_column import (
    IcebergTableColumn,
    IcebergTableColumnModel,
)


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

    Constructs an object of type IcebergTable with the provided properties.

    Parameters
    __________
    name : str
        Name of the iceberg table
    comment : str, optional
        user comment associated to an object in the dictionary
    change_tracking : bool, optional
        True if change tracking is enabled, allowing streams and CHANGES to be used on the entity.
    max_data_extension_time_in_days : int, optional
        Maximum number of days to extend data retention beyond the retention period to prevent a stream becoming stale.
    external_volume : str, optional
        Name of an external volume that will be used for persisted Iceberg metadata and data files.
    data_retention_time_in_days : int, optional
        number of days to retain the old version of deleted/updated data
    catalog_sync : str, optional
        Name of the catalog integration to sync this table
    catalog : str, optional
        Name of the catalog integration to use for iceberg tables
    storage_serialization_policy : str, optional
        Storage serialization policy used for managed Iceberg table. This include encodings and compressions
    created_on : datetime, optional
        Date and time when the iceberg table was created — **Read-only:** *any user-provided value will be ignored.*
    database_name : str, optional
        Database in which the iceberg table is stored — **Read-only:** *any user-provided value will be ignored.*
    schema_name : str, optional
        Schema in which the iceberg table is stored — **Read-only:** *any user-provided value will be ignored.*
    owner : str, optional
        Role that owns the iceberg table — **Read-only:** *any user-provided value will be ignored.*
    owner_role_type : str, optional
        The type of role that owns the iceberg table — **Read-only:** *any user-provided value will be ignored.*
    iceberg_table_type : str, optional
        Type of Iceberg table. UNMANAGED if the table is not managed by Snowflake. NOT ICEBERG otherwise — **Read-only:** *any user-provided value will be ignored.*
    catalog_table_name : str, optional
        Name of the table as recognized by the catalog.
    catalog_namespace : str, optional
        Catalog namespace for the table. The namespace defined when the table was created. Otherwise, the default namespace associated with the catalog integration used by the table. If you’re syncing the table to Snowflake Open Catalog, the default is null.
    can_write_metadata : str, optional
        Signifies whether Snowflake can write metadata to the location specified by the file_path — **Read-only:** *any user-provided value will be ignored.*
    cluster_by : list[str], optional
        Specifies one or more columns or column expressions in the table as the clustering key.
    columns : list[IcebergTableColumn], optional

    base_location : str, optional
        The path to a directory where Snowflake can write data and metadata files for the table.
    replace_invalid_characters : bool, optional
        Specifies whether to replace invalid characters in the column names
    auto_refresh : bool, optional
        Specifies whether to automatically refresh the table metadata — **Read-only:** *any user-provided value will be ignored.*
    metadata_file_path : str, optional
        Specifies the relative path of the Iceberg metadata file to use for column definitions.
    constraints : list[Constraint], optional
    """

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

    comment: Optional[StrictStr] = None

    change_tracking: Optional[StrictBool] = None

    max_data_extension_time_in_days: Optional[StrictInt] = None

    external_volume: Optional[StrictStr] = None

    data_retention_time_in_days: Optional[StrictInt] = None

    catalog_sync: Optional[StrictStr] = None

    catalog: Optional[StrictStr] = None

    storage_serialization_policy: Optional[StrictStr] = None

    created_on: Optional[datetime] = None

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

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

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

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

    iceberg_table_type: Optional[StrictStr] = None

    catalog_table_name: Optional[StrictStr] = None

    catalog_namespace: Optional[StrictStr] = None

    can_write_metadata: Optional[StrictStr] = None

    cluster_by: Optional[List[StrictStr]] = None

    columns: Optional[List[IcebergTableColumn]] = None

    base_location: Optional[StrictStr] = None

    replace_invalid_characters: Optional[StrictBool] = None

    auto_refresh: Optional[StrictBool] = None

    metadata_file_path: Optional[StrictStr] = None

    constraints: Optional[List[Constraint]] = None

    __properties = [
        "name",
        "comment",
        "change_tracking",
        "max_data_extension_time_in_days",
        "external_volume",
        "data_retention_time_in_days",
        "catalog_sync",
        "catalog",
        "storage_serialization_policy",
        "created_on",
        "database_name",
        "schema_name",
        "owner",
        "owner_role_type",
        "iceberg_table_type",
        "catalog_table_name",
        "catalog_namespace",
        "can_write_metadata",
        "cluster_by",
        "columns",
        "base_location",
        "replace_invalid_characters",
        "auto_refresh",
        "metadata_file_path",
        "constraints",
    ]

    @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("storage_serialization_policy")
    def storage_serialization_policy_validate_enum(cls, v):
        if v is None:
            return v
        if v not in ("COMPATIBLE", "OPTIMIZED"):
            raise ValueError("must validate the enum values ('COMPATIBLE','OPTIMIZED')")
        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

    @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("owner")
    def owner_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("owner_role_type")
    def owner_role_type_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) -> IcebergTable:
        """Create an instance of IcebergTable 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",
                    "database_name",
                    "schema_name",
                    "owner",
                    "owner_role_type",
                    "iceberg_table_type",
                    "can_write_metadata",
                    "auto_refresh",
                }
            )

        _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 columns (list)
        _items = []
        if self.columns:
            for _item in self.columns:
                if _item:
                    _items.append(_item.to_dict())
            _dict["columns"] = _items

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

        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) -> IcebergTable:
        """Create an instance of IcebergTable from a dict."""
        if obj is None:
            return None

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

        _obj = IcebergTable.model_validate(
            {
                "name": obj.get("name"),
                "comment": obj.get("comment"),
                "change_tracking": obj.get("change_tracking"),
                "max_data_extension_time_in_days": obj.get("max_data_extension_time_in_days"),
                "external_volume": obj.get("external_volume"),
                "data_retention_time_in_days": obj.get("data_retention_time_in_days"),
                "catalog_sync": obj.get("catalog_sync"),
                "catalog": obj.get("catalog"),
                "storage_serialization_policy": obj.get("storage_serialization_policy"),
                "created_on": obj.get("created_on"),
                "database_name": obj.get("database_name"),
                "schema_name": obj.get("schema_name"),
                "owner": obj.get("owner"),
                "owner_role_type": obj.get("owner_role_type"),
                "iceberg_table_type": obj.get("iceberg_table_type"),
                "catalog_table_name": obj.get("catalog_table_name"),
                "catalog_namespace": obj.get("catalog_namespace"),
                "can_write_metadata": obj.get("can_write_metadata"),
                "cluster_by": obj.get("cluster_by"),
                "columns": [IcebergTableColumn.from_dict(_item) for _item in obj.get("columns")]
                if obj.get("columns") is not None
                else None,
                "base_location": obj.get("base_location"),
                "replace_invalid_characters": obj.get("replace_invalid_characters"),
                "auto_refresh": obj.get("auto_refresh"),
                "metadata_file_path": obj.get("metadata_file_path"),
                "constraints": [Constraint.from_dict(_item) for _item in obj.get("constraints")]
                if obj.get("constraints") is not None
                else None,
            }
        )

        return _obj


class IcebergTableModel:
    def __init__(
        self,
        name: str,
        # optional properties
        comment: Optional[str] = None,
        change_tracking: Optional[bool] = None,
        max_data_extension_time_in_days: Optional[int] = None,
        external_volume: Optional[str] = None,
        data_retention_time_in_days: Optional[int] = None,
        catalog_sync: Optional[str] = None,
        catalog: Optional[str] = None,
        storage_serialization_policy: Optional[str] = None,
        created_on: Optional[datetime] = None,
        database_name: Optional[str] = None,
        schema_name: Optional[str] = None,
        owner: Optional[str] = None,
        owner_role_type: Optional[str] = None,
        iceberg_table_type: Optional[str] = None,
        catalog_table_name: Optional[str] = None,
        catalog_namespace: Optional[str] = None,
        can_write_metadata: Optional[str] = None,
        cluster_by: Optional[list[str]] = None,
        columns: Optional[list[IcebergTableColumn]] = None,
        base_location: Optional[str] = None,
        replace_invalid_characters: Optional[bool] = None,
        auto_refresh: Optional[bool] = None,
        metadata_file_path: Optional[str] = None,
        constraints: Optional[list[Constraint]] = None,
    ):
        """A model object representing the IcebergTable resource.

        Constructs an object of type IcebergTable with the provided properties.

        Parameters
        __________
        name : str
            Name of the iceberg table
        comment : str, optional
            user comment associated to an object in the dictionary
        change_tracking : bool, optional
            True if change tracking is enabled, allowing streams and CHANGES to be used on the entity.
        max_data_extension_time_in_days : int, optional
            Maximum number of days to extend data retention beyond the retention period to prevent a stream becoming stale.
        external_volume : str, optional
            Name of an external volume that will be used for persisted Iceberg metadata and data files.
        data_retention_time_in_days : int, optional
            number of days to retain the old version of deleted/updated data
        catalog_sync : str, optional
            Name of the catalog integration to sync this table
        catalog : str, optional
            Name of the catalog integration to use for iceberg tables
        storage_serialization_policy : str, optional
            Storage serialization policy used for managed Iceberg table. This include encodings and compressions
        created_on : datetime, optional
            Date and time when the iceberg table was created.
        database_name : str, optional
            Database in which the iceberg table is stored
        schema_name : str, optional
            Schema in which the iceberg table is stored
        owner : str, optional
            Role that owns the iceberg table
        owner_role_type : str, optional
            The type of role that owns the iceberg table
        iceberg_table_type : str, optional
            Type of Iceberg table. UNMANAGED if the table is not managed by Snowflake. NOT ICEBERG otherwise.
        catalog_table_name : str, optional
            Name of the table as recognized by the catalog.
        catalog_namespace : str, optional
            Catalog namespace for the table. The namespace defined when the table was created. Otherwise, the default namespace associated with the catalog integration used by the table. If you’re syncing the table to Snowflake Open Catalog, the default is null.
        can_write_metadata : str, optional
            Signifies whether Snowflake can write metadata to the location specified by the file_path.
        cluster_by : list[str], optional
            Specifies one or more columns or column expressions in the table as the clustering key.
        columns : list[IcebergTableColumn], optional

        base_location : str, optional
            The path to a directory where Snowflake can write data and metadata files for the table.
        replace_invalid_characters : bool, optional
            Specifies whether to replace invalid characters in the column names
        auto_refresh : bool, optional
            Specifies whether to automatically refresh the table metadata
        metadata_file_path : str, optional
            Specifies the relative path of the Iceberg metadata file to use for column definitions.
        constraints : list[Constraint], optional
        """
        self.name = name
        self.comment = comment
        self.change_tracking = change_tracking
        self.max_data_extension_time_in_days = max_data_extension_time_in_days
        self.external_volume = external_volume
        self.data_retention_time_in_days = data_retention_time_in_days
        self.catalog_sync = catalog_sync
        self.catalog = catalog
        self.storage_serialization_policy = storage_serialization_policy
        self.created_on = created_on
        self.database_name = database_name
        self.schema_name = schema_name
        self.owner = owner
        self.owner_role_type = owner_role_type
        self.iceberg_table_type = iceberg_table_type
        self.catalog_table_name = catalog_table_name
        self.catalog_namespace = catalog_namespace
        self.can_write_metadata = can_write_metadata
        self.cluster_by = cluster_by
        self.columns = columns
        self.base_location = base_location
        self.replace_invalid_characters = replace_invalid_characters
        self.auto_refresh = auto_refresh
        self.metadata_file_path = metadata_file_path
        self.constraints = constraints

    __properties = [
        "name",
        "comment",
        "change_tracking",
        "max_data_extension_time_in_days",
        "external_volume",
        "data_retention_time_in_days",
        "catalog_sync",
        "catalog",
        "storage_serialization_policy",
        "created_on",
        "database_name",
        "schema_name",
        "owner",
        "owner_role_type",
        "iceberg_table_type",
        "catalog_table_name",
        "catalog_namespace",
        "can_write_metadata",
        "cluster_by",
        "columns",
        "base_location",
        "replace_invalid_characters",
        "auto_refresh",
        "metadata_file_path",
        "constraints",
    ]

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

    def _to_model(self):
        return IcebergTable(
            name=self.name,
            comment=self.comment,
            change_tracking=self.change_tracking,
            max_data_extension_time_in_days=self.max_data_extension_time_in_days,
            external_volume=self.external_volume,
            data_retention_time_in_days=self.data_retention_time_in_days,
            catalog_sync=self.catalog_sync,
            catalog=self.catalog,
            storage_serialization_policy=self.storage_serialization_policy,
            created_on=self.created_on,
            database_name=self.database_name,
            schema_name=self.schema_name,
            owner=self.owner,
            owner_role_type=self.owner_role_type,
            iceberg_table_type=self.iceberg_table_type,
            catalog_table_name=self.catalog_table_name,
            catalog_namespace=self.catalog_namespace,
            can_write_metadata=self.can_write_metadata,
            cluster_by=self.cluster_by,
            columns=[x._to_model() for x in self.columns] if self.columns is not None else None,
            base_location=self.base_location,
            replace_invalid_characters=self.replace_invalid_characters,
            auto_refresh=self.auto_refresh,
            metadata_file_path=self.metadata_file_path,
            constraints=[x._to_model() for x in self.constraints] if self.constraints is not None else None,
        )

    @classmethod
    def _from_model(cls, model) -> IcebergTableModel:
        return IcebergTableModel(
            name=model.name,
            comment=model.comment,
            change_tracking=model.change_tracking,
            max_data_extension_time_in_days=model.max_data_extension_time_in_days,
            external_volume=model.external_volume,
            data_retention_time_in_days=model.data_retention_time_in_days,
            catalog_sync=model.catalog_sync,
            catalog=model.catalog,
            storage_serialization_policy=model.storage_serialization_policy,
            created_on=model.created_on,
            database_name=model.database_name,
            schema_name=model.schema_name,
            owner=model.owner,
            owner_role_type=model.owner_role_type,
            iceberg_table_type=model.iceberg_table_type,
            catalog_table_name=model.catalog_table_name,
            catalog_namespace=model.catalog_namespace,
            can_write_metadata=model.can_write_metadata,
            cluster_by=model.cluster_by,
            columns=[IcebergTableColumnModel._from_model(x) for x in model.columns] if model.columns else None,
            base_location=model.base_location,
            replace_invalid_characters=model.replace_invalid_characters,
            auto_refresh=model.auto_refresh,
            metadata_file_path=model.metadata_file_path,
            constraints=[ConstraintModel._from_model(x) for x in model.constraints] if model.constraints else None,
        )

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

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

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

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

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


IcebergTable._model_class = IcebergTableModel
