from typing import Union

from fastapi import status
from fastapi.responses import JSONResponse
from fastapi.exceptions import HTTPException

from databases import (
    BuildLivingSpace,
    BuildParts,
    Build,
    Events,
    Event2Occupant,
    OccupantTypes,
)
from api_validations.validations_request import RegisterEvents2Occupant
from api_events.events.abstract_class import MethodToEvent, ActionsSchema
from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject
from api_validations.core_response import AlchemyJsonResponse


class EventBindOccupantEventMethods(MethodToEvent):
    event_type = "UPDATE"
    __event_keys__ = {
        "5702f0a9-fe8f-4aae-922e-6e04b497ef6a": "bind_events_occupant_super_user",
    }

    @classmethod
    def bind_events_occupant_super_user(
        cls,
        data: RegisterEvents2Occupant,
        token_dict: Union[EmployeeTokenObject, OccupantTokenObject],
    ):

        if not str(token_dict.user_type) == "1":
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="This employee is not authorized to add event to this occupant",
            )

        occupants_build_part = BuildParts.filter_one(
            BuildParts.uu_id == data.build_part_uu_id,
            BuildParts.active == True,
        ).data
        if not occupants_build_part:
            return JSONResponse(
                content={
                    "completed": False,
                    "message": "This employee is not authorized to add event to this building",
                    "data": {},
                },
                status_code=status.HTTP_404_NOT_FOUND,
            )

        occupant_occupant_type = OccupantTypes.filter_by_one(
            uu_id=data.occupant_uu_id
        ).data
        if not occupant_occupant_type:
            return JSONResponse(
                content={
                    "completed": False,
                    "message": "Occupant Types is not found",
                    "data": {},
                },
                status_code=status.HTTP_404_NOT_FOUND,
            )

        events_to_add_to_occupant = Events.filter_all(
            Events.uu_id.in_(list(data.event_uu_id_list)),
        )
        if not events_to_add_to_occupant.data:
            return JSONResponse(
                content={
                    "completed": False,
                    "message": "Events are not found. Please contact with your manager",
                    "data": {},
                },
                status_code=status.HTTP_404_NOT_FOUND,
            )

        employee_is_authorized = Build.select_action(
            employee_id=token_dict.selected_company.employee_id,
            filter_expr=[Build.id == occupants_build_part.build_id],
        )
        if not employee_is_authorized.first():
            return JSONResponse(
                content={
                    "completed": False,
                    "data": {},
                },
                status_code=status.HTTP_401_UNAUTHORIZED,
            )

        occupant_to_add_event = BuildLivingSpace.filter_one(
            BuildLivingSpace.build_parts_id == occupants_build_part.id,
            BuildLivingSpace.occupant_type == occupant_occupant_type.id,
            BuildLivingSpace.active == True,
        ).data
        if not occupant_to_add_event:
            return JSONResponse(
                content={
                    "completed": False,
                    "message": "Occupant is not found or this employee is not authorized to add event to this occupant",
                    "data": {},
                },
                status_code=status.HTTP_404_NOT_FOUND,
            )

        events_added = []
        for event in events_to_add_to_occupant.data:
            if Event2Occupant.find_or_create(
                event_id=event.id,
                event_uu_id=str(event.uu_id),
                build_living_space_id=occupant_to_add_event.id,
                build_living_space_uu_id=str(occupant_to_add_event.uu_id),
                is_confirmed=True,
            ):
                events_added.append(event)

        if events_added:
            Events.save()
            return JSONResponse(
                content={
                    "completed": True,
                    "message": "Event added to occupant",
                    "data": [event.get_dict() for event in events_added],
                },
                status_code=status.HTTP_200_OK,
            )
        return JSONResponse(
            content={
                "completed": False,
                "message": "Event is not added to occupant",
                "data": [],
            },
            status_code=status.HTTP_404_NOT_FOUND,
        )


class EventBindEmployeeEventMethods(MethodToEvent):

    event_type = "UPDATE"
    __event_keys__ = {
        "c93a3009-65a0-498d-9191-04484d5cde81": "bind_events_employee",
    }

    @classmethod
    def bind_events_employee(
        cls,
        data: RegisterEvents2Occupant,
        token_dict: Union[EmployeeTokenObject, OccupantTokenObject],
    ):
        return token_dict.available_event(data=data, token_dict=token_dict)


EventBindOccupantEventMethod = EventBindOccupantEventMethods(
    action=ActionsSchema(endpoint="/bind/events/occupant")
)
EventBindEmployeeEventMethod = EventBindEmployeeEventMethods(
    action=ActionsSchema(endpoint="/bind/events/employee")
)
