"""
Description: This file contains the models for the use in the system controller itself.
Authors: Martin Altenburger
TODO: Is it possible to use the models from the configuration also for the system controller?\
    Or could we use less modells?
"""

from datetime import datetime
from typing import Dict, List, Optional, Union
from pandas import DataFrame
from pydantic import BaseModel, ConfigDict
from filip.models.ngsi_v2.base import NamedMetadata
from filip.models.ngsi_v2.context import ContextEntity
from encodapy.config.models import AttributeModel, CommandModel
from encodapy.config.types import AttributeTypes
from encodapy.utils.units import DataUnits

class InputDataAttributeModel(BaseModel):
    """
    Model for a attribute of input data of the system controller.

    Contains:
    - id: The id of the input data attribute
    - data: The input data as a DataFrame or a single value
    - unit: The unit of the input data
    - data_type: The type of the input data (AttributeTypes)
    - data_available: If the data is available
    - latest_timestamp_input: The latest timestamp of the input data from the query or None,\
        if the data is not available
    """

    model_config = ConfigDict(arbitrary_types_allowed=True)

    id: str
    data: Union[str, float, int, bool, Dict, List, DataFrame, None]
    unit: Union[DataUnits, None] = None
    data_type: AttributeTypes
    data_available: bool
    latest_timestamp_input: Union[datetime, None]


class InputDataEntityModel(BaseModel):
    """
    Model for the input data of the system controller.

    Contains:
    - id: The id of the input data entity
    - attributes: List of the input data attributes as InputDataAttributeModel
    """

    id: str
    attributes: List[InputDataAttributeModel]


class StaticDataEntityModel(InputDataEntityModel):
    """
    Model for the static data of the system controller, same like InputDataEntityModel.

    Contains:
    - id: The id of the input data entity
    - attributes: List of the input data attributes as InputDataAttributeModel
    """


class OutputDataAttributeModel(BaseModel):
    """
    Model for a attribute of output data of the system controller - status based on the status\
        of the interface.

    Contains:
    - id: The id of the output data attribute
    - latest_timestamp_output: The latest timestamp of the output data from the query or None,\
        if the data is not available
    """

    model_config = ConfigDict(arbitrary_types_allowed=True)

    id: str
    latest_timestamp_output: Optional[Union[datetime, None]] = None


class OutputDataEntityModel(BaseModel):
    """
    Model for the status of the output data of the system controller.

    Contains:
    - id: The id of the output entity
    - latest_timestamp_output: The latest timestamp of the output data from the query or None,\
        if the data is not available

    - attributes: List of the output data attributes as OutputDataAttributeModel
    - commands: List of the output data commands as OutputDataCommandModel

    """

    id: str
    attributes: Optional[List[AttributeModel]] = []
    attributes_status: Optional[List[OutputDataAttributeModel]] = []
    commands: Optional[List[CommandModel]] = []


class InputDataModel(BaseModel):
    """
    Model for the input data of the system controller.

    Contains:
    - input_entities: List of the input data entities as InputDataEntityModel
    - output_entities: List of the output data entities as OutputDataEntityModel
    - static_entities: List of the static data entities as StaticDataEntityModel
    """

    input_entities: list[InputDataEntityModel]
    output_entities: list[OutputDataEntityModel]
    static_entities: list[StaticDataEntityModel]


# class ContextDataModel(BaseModel):
#     """
#     Model for the context data of the system controller.

#     Contains:
#     - input_entitys: List of the context data entitys as ContexttDataEntityModel

#     """

#     context_entities: list[InputDataEntityModel]


class OutputDataModel(BaseModel):
    """
    Model for the output data of the system controller.

    Contains:
    - output_entitys: List of the output data entitys as OutputDataEntityModel
    """

    entities: list[OutputDataEntityModel]


class ComponentModel(BaseModel):
    """
    Model for the dataflow (input/output) of the controller.

    Contains:
    - entity: The entity (input / output) of the datapoint for the controller
    - attribute: The attribute of the datapoint for the controller
    """

    entity_id: str
    attribute_id: str


class DataTransferComponentModel(ComponentModel):
    """
    Model for the components of the data transfer between calculation and the basic service.

    Contains:
    - entity_id: The id of the entity of the component
    - attribute_id: The id of the attribute of the component
    - value: The output data value as OutputDataModel
    - unit: The unit of the output data
    - timestamp: The timestamp of the output
    """

    model_config = ConfigDict(arbitrary_types_allowed=True)

    value: Union[str, float, int, bool, Dict, List, DataFrame, None]
    unit: Union[DataUnits, None] = None
    timestamp: Optional[Union[datetime, None]] = None


class DataTransferModel(BaseModel):
    """
    Model for the data transfer between calculation and the basic service.

    Contains:
    - components: List of the components of the data transfer as DataTransferComponentModel
    """

    components: list[DataTransferComponentModel] = []


# Models for the Fiware Connection
class MetaDataModel(BaseModel):
    """
    Model for the metadata of datapoints of the controller.

    Contains:
    - timestamp: The timestamp of the data
    - unit: The unit of the data
    """

    timestamp: Union[datetime, None] = None
    unit: Union[DataUnits, None] = None


class FiwareDatapointParameter(BaseModel):
    """
    Model for the Fiware datapoint parameter.
    Contains:
        entity (ContextEntity): The entity of the datapoint
        attribute (AttributeModel): The attribute of the datapoint
        metadata (list[NamedMetadata]): The metadata of the attribute
    Args:
        BaseModel (BaseModel): Pydantic BaseModel of a datapoint in fiware
    """
    entity: ContextEntity
    attribute: AttributeModel
    metadata: list[NamedMetadata]

class FiwareAuth(BaseModel):
    """
    Base model for the Fiware authentication.
    Contains:
        client_id (str): The client id
        client_secret (str): The client secret
        token_url (str): The token url
        baerer_token (str): The baerer token
    """
    client_id:Optional[str]=None
    client_secret:Optional[str]=None
    token_url:Optional[str]=None
    baerer_token:Optional[str]=None

class FiwareParameter(BaseModel):
    """
    Model for the Fiware connection parameters.
    Contains:
        cb_url (str): The context broker url
        service (str): The service
        service_path (str): The service path
        authentication (Optional[Union[FiwareAuth, None]]): The authentication
    """
    cb_url:str
    service:str
    service_path:str
    authentication: Optional[Union[FiwareAuth, None]] = None

class DatabaseParameter(BaseModel):
    """
    Model for the database connection parameters.
    Contains:
        crate_db_url (str): The CrateDB url
        crate_db_user (Optional[str]): The CrateDB user
        crate_db_pw (Optional[str]): The CrateDB password
        crate_db_ssl (Optional[bool]): The CrateDB ssl
    """
    crate_db_url:str
    crate_db_user:Optional[Union[str, None]]=None
    crate_db_pw:Optional[str]=""
    crate_db_ssl:Optional[bool]=True

class FiwareConnectionParameter(BaseModel):
    """
    Model for the Fiware connection parameters.
    Contains:
        fiware_params (FiwareParameter): The Fiware parameters
        database_params (DatabaseParameter): The database parameters
    """
    fiware_params:FiwareParameter
    database_params:DatabaseParameter
