import typing

from databases import (
    Build,
    BuildSites,
)

from api_validations.validations_request import (
    InsertBuildArea,
    UpdateBuildArea,
    ListOptions,
)

from api_validations.validations_response import BuildSitesResponse

from ApiServices.api_handlers import AlchemyJsonResponse
from api_events.events.abstract_class import MethodToEvent, ActionsSchema
from api_objects.auth.token_objects import EmployeeTokenObject, OccupantTokenObject


class BuildSitesListEventMethods(MethodToEvent):

    event_type = "SELECT"
    __event_keys__ = {
        "6798414c-6c7d-47f0-9d8b-6935a0f51c2e": "build_sites_list",
    }
    __event_validation__ = {
        "6798414c-6c7d-47f0-9d8b-6935a0f51c2e": BuildSitesResponse,
    }

    @classmethod
    def build_sites_list(
        cls,
        list_options: ListOptions,
        token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
    ):
        if isinstance(token_dict, OccupantTokenObject):
            occupants_build = Build.filter_one(
                Build.id == token_dict.selected_occupant.build_id,
            ).data
            BuildSites.pre_query = BuildSites.filter_all(
                BuildSites.address_id == occupants_build.address_id,
            ).query
        elif isinstance(token_dict, EmployeeTokenObject):
            employees_build = Build.select_action(
                employee_id=token_dict.selected_company.employee_id
            )
            employees_build_list = [build.address_id for build in employees_build.all()]
            if not employees_build_list:
                BuildSites.raise_http_exception(
                    status_code="HTTP_404_NOT_FOUND",
                    error_case="NOT_FOUND",
                    message="Employee has no build sites registered",
                    data={},
                )
            BuildSites.pre_query = BuildSites.filter_all(
                BuildSites.address_id.in_(employees_build_list)
            ).query
        BuildSites.filter_attr = list_options
        records = BuildSites.filter_all()
        return AlchemyJsonResponse(
            completed=True,
            message="Building sites listed successfully",
            result=records,
            cls_object=BuildSites,
            filter_attributes=list_options,
            response_model=BuildSitesResponse,
        )


class BuildSitesCreateEventMethods(MethodToEvent):

    event_type = "CREATE"
    __event_keys__ = {
        "57edc8bf-8f29-4e75-b5e1-9ca0139a3fda": "build_sites_create",
    }
    __event_validation__ = {
        "57edc8bf-8f29-4e75-b5e1-9ca0139a3fda": InsertBuildArea,
    }

    @classmethod
    def build_area_create(
        cls,
        data: InsertBuildArea,
        token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
    ):
        if isinstance(token_dict, OccupantTokenObject):
            if not token_dict.selected_occupant.build_uuid == data.build_uu_id:
                BuildSites.raise_http_exception(
                    status_code="HTTP_403_FORBIDDEN",
                    error_case="UNAUTHORIZED",
                    message=f"Occupant can not create build sites for {data.build_uu_id}",
                    data={
                        "build_uu_id": data.build_uu_id,
                    },
                )
        elif isinstance(token_dict, EmployeeTokenObject):
            build_ids = Build.select_action(
                employee_id=token_dict.selected_company.employee_id
            ).all()
            if not str(data.build_uu_id) in [str(build.uu_id) for build in build_ids]:
                BuildSites.raise_http_exception(
                    status_code="HTTP_403_FORBIDDEN",
                    error_case="UNAUTHORIZED",
                    message=f"Employee can not create build sites for {data.build_uu_id}",
                    data={
                        "build_uu_id": data.build_uu_id,
                    },
                )
        data_dict = data.excluded_dump()
        site = BuildSites.insert_one(data_dict).data
        return AlchemyJsonResponse(
            completed=True, message="Building site created successfully", result=site
        )


class BuildSitesUpdateEventMethods(MethodToEvent):

    event_type = "UPDATE"
    __event_keys__ = {
        "b18e8e37-a62b-4a84-9972-ba17121ed393": "build_sites_update",
    }
    __event_validation__ = {
        "b18e8e37-a62b-4a84-9972-ba17121ed393": UpdateBuildArea,
    }

    @classmethod
    def build_area_update(
        cls,
        build_uu_id: str,
        data: UpdateBuildArea,
        token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
    ):
        site = BuildSites.update_one(build_uu_id, data).data
        return AlchemyJsonResponse(
            completed=True, message="Building site updated successfully", result=site
        )


class BuildSitesPatchEventMethods(MethodToEvent):

    event_type = "PATCH"
    __event_keys__ = {
        "39ba1d78-ff0d-4ec7-a363-b457cbf199a0": "build_sites_patch",
    }
    __event_validation__ = {
        "39ba1d78-ff0d-4ec7-a363-b457cbf199a0": None,
    }

    @classmethod
    def build_area_patch(
        cls,
        build_uu_id: str,
        data,
        token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
    ):
        site = BuildSites.patch_one(build_uu_id, data).data
        return AlchemyJsonResponse(
            completed=True, message="Building site patched successfully", result=site
        )


BuildSitesListEventMethod = BuildSitesListEventMethods(
    action=ActionsSchema(endpoint="/building/sites/list")
)
BuildSitesCreateEventMethod = BuildSitesCreateEventMethods(
    action=ActionsSchema(endpoint="/building/sites/create")
)
BuildSitesUpdateEventMethod = BuildSitesUpdateEventMethods(
    action=ActionsSchema(endpoint="/building/sites/update")
)
BuildSitesPatchEventMethod = BuildSitesPatchEventMethods(
    action=ActionsSchema(endpoint="/building/sites/patch")
)
