from typing import Dict, List, Any, Optional


class Parameter:
    def __init__(self, name: str, type_: str, nullable: bool):
        self.name = name
        self.type_ = type_
        self.nullable = nullable


class ReturnType:
    def __init__(self, type_: str, isEntity: bool, isCollection: bool, nullable: bool):
        self.type_ = type_
        self.isEntity = isEntity
        self.isCollection = isCollection
        self.nullable = nullable


class Operation:
    def __init__(self, name: str, parameters: List[Parameter], returnType: Optional[ReturnType]):
        self.name = name
        self.parameters = parameters
        self.returnType = returnType


class Property:
    def __init__(self, fieldName: str, type_: str, nullable: bool, default: Any, maxLength: Optional[int]):
        self.fieldName = fieldName
        self.type_ = type_
        self.nullable = nullable
        self.default = default
        self.maxLength = maxLength


class NavigationProperty:
    def __init__(self, entityTypeName: str, multiplicity: str, keyLocal: List[str], keyRemote: List[str]):
        self.entityTypeName = entityTypeName
        self.multiplicity = multiplicity
        self.keyLocal = keyLocal
        self.keyRemote = keyRemote


class EntityType:
    def __init__(self, tableName: str, entitySetName: str, key: List[str], properties: Dict[str, Property], calculatedProperties: List[str], navigationProperties: Dict[str, NavigationProperty]):
        self.tableName = tableName
        self.entitySetName = entitySetName
        self.key = key
        self.properties = properties
        self.calculatedProperties = calculatedProperties
        self.navigationProperties = navigationProperties


class Multiplicity:
    def __init__(self, multi: str, single: str):
        self.multi = multi
        self.single = single


class Metadata:
    def __init__(self, dialect: str, version: str, description: str, namespace: str, max_: int, multiplicity: Multiplicity, entityTypes: Dict[str, EntityType], functions: List[Operation], actions: List[Operation]):
        self.dialect = dialect
        self.version = version
        self.description = description
        self.namespace = namespace
        self.max_ = max_
        self.multiplicity = multiplicity
        self.entityTypes = entityTypes
        self.functions = functions
        self.actions = actions


class OperationsDefinition:
    def __init__(self, functions: List[Operation], actions: List[Operation]):
        self.functions = functions
        self.actions = actions
