from datetime import datetime
from typing import NamedTuple, Optional

from bclearer_orchestration_services.identification_services.b_identity_ecosystem.bie_id_creation_module.common_knowledge.types.bie_vector_structure_types import (
    BieVectorStructureTypes,
)
from bclearer_orchestration_services.identification_services.b_identity_ecosystem.bie_id_creation_module.identity_vectors.bie_identity_vector_base import (
    BieIdentityVectorBase,
)
from bclearer_orchestration_services.identification_services.b_identity_ecosystem.common_knowledge.bie_enums import (
    BieEnums,
)
from bclearer_orchestration_services.identification_services.b_identity_ecosystem.objects.bie_ids import (
    BieIds,
)


def _validate_places(
    places: NamedTuple,
) -> None:
    if not isinstance(places, tuple):
        raise TypeError(
            "places must be a NamedTuple"
        )

    for field_name in places._fields:
        value = getattr(places, field_name)

        if value is None:
            raise ValueError(
                f"places field '{field_name}' must not be None"
            )


# --- Operating System ---


class OperatingSystemObjectIdentityVectorPlaces(
    NamedTuple,
):
    operating_system_type_bie_id: BieIds
    machine_sid: str


class OperatingSystemObjectIdentityVector(
    BieIdentityVectorBase,
):
    def __init__(
        self,
        places: OperatingSystemObjectIdentityVectorPlaces,
    ):
        _validate_places(places=places)

        self._places = places

    @property
    def bie_domain_type(
        self,
    ) -> Optional[BieEnums]:
        return None

    @property
    def bie_vector_structure_type(
        self,
    ) -> BieVectorStructureTypes:
        return (
            BieVectorStructureTypes.MULTI_DIMENSIONAL_ORDER_SENSITIVE
        )

    def input_objects(self) -> list:
        return [
            self._places.operating_system_type_bie_id,
            self._places.machine_sid,
        ]


# --- OS User Profile ---


class OsUserProfileObjectIdentityVectorPlaces(
    NamedTuple,
):
    os_user_profile_type_bie_id: BieIds
    user_sid: str
    operating_system_type_bie_id: BieIds


class OsUserProfileObjectIdentityVector(
    BieIdentityVectorBase,
):
    def __init__(
        self,
        places: OsUserProfileObjectIdentityVectorPlaces,
    ):
        _validate_places(places=places)

        self._places = places

    @property
    def bie_domain_type(
        self,
    ) -> Optional[BieEnums]:
        return None

    @property
    def bie_vector_structure_type(
        self,
    ) -> BieVectorStructureTypes:
        return (
            BieVectorStructureTypes.MULTI_DIMENSIONAL_ORDER_SENSITIVE
        )

    def input_objects(self) -> list:
        return [
            self._places.os_user_profile_type_bie_id,
            self._places.user_sid,
            self._places.operating_system_type_bie_id,
        ]


# --- OS User Profile Session ---


class OsUserProfileSessionObjectIdentityVectorPlaces(
    NamedTuple,
):
    os_user_session_type_bie_id: BieIds
    windows_session_id: int
    session_start_date_time: datetime
    owning_operating_system_bie_id: BieIds

    @property
    def os_user_session_id(self) -> int:
        return self.windows_session_id


class OsUserProfileSessionObjectIdentityVector(
    BieIdentityVectorBase,
):
    def __init__(
        self,
        places: OsUserProfileSessionObjectIdentityVectorPlaces,
    ):
        _validate_places(places=places)

        self._places = places

    @property
    def bie_domain_type(
        self,
    ) -> Optional[BieEnums]:
        return None

    @property
    def bie_vector_structure_type(
        self,
    ) -> BieVectorStructureTypes:
        return (
            BieVectorStructureTypes.MULTI_DIMENSIONAL_ORDER_SENSITIVE
        )

    def input_objects(self) -> list:
        return [
            self._places.os_user_session_type_bie_id,
            self._places.os_user_session_id,
            self._places.session_start_date_time,
            self._places.owning_operating_system_bie_id,
        ]
