import typing

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

from databases import (
    Build,
    BuildDecisionBook,
    Companies,
    OccupantTypes,
)

from api_validations.validations_request import (
    InsertDecisionBook,
    ListOptions,
)

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


class DecisionBookListEventMethods(MethodToEvent):

    event_type = "SELECT"
    __event_keys__ = {
        "5c10d6ae-2aee-4243-a7c3-94826d028d13": "building_decision_book_list",
    }
    __event_validation__ = {"5c10d6ae-2aee-4243-a7c3-94826d028d13": None}

    @classmethod
    def building_decision_book_list(
        cls,
        list_options: ListOptions,
        token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
    ):
        records = []
        if isinstance(token_dict, EmployeeTokenObject):
            build_id_list_query = Build.select_action(
                employee_id=token_dict.selected_company.employee_id
            )
            build_id_list = build_id_list_query.all()
            if not build_id_list:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail=f"No building is match with given Employee UUID {token_dict.selected_company.employee_uu_id}",
                )
            BuildDecisionBook.filter_attr = list_options
            records = BuildDecisionBook.filter_all(
                BuildDecisionBook.build_id.in_([build.id for build in build_id_list]),
            )
        elif isinstance(token_dict, OccupantTokenObject):
            BuildDecisionBook.filter_attr = list_options
            records = BuildDecisionBook.filter_all(
                BuildDecisionBook.build_id == token_dict.selected_occupant.build_id,
            )
        return AlchemyJsonResponse(
            completed=True,
            message="DecisionBook are listed successfully",
            result=records,
        )


class DecisionBookCreateEventMethods(MethodToEvent):

    event_type = "CREATE"
    __event_keys__ = {
        "0a68cb44-271a-4829-81f6-cd99a5f326b4": "building_decision_book_create",
    }
    __event_validation__ = {"0a68cb44-271a-4829-81f6-cd99a5f326b4": InsertDecisionBook}

    @classmethod
    def building_decision_book_create(
        cls,
        data: InsertDecisionBook,
        token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
    ):
        data_dict = data.excluded_dump()
        if isinstance(token_dict, EmployeeTokenObject):
            Build.pre_query = Build.select_action(
                employee_id=token_dict.selected_company.employee_id
            )
            build = Build.filter_one(
                Build.uu_id == data.build_uu_id,
            ).data
            if not build:
                raise HTTPException(
                    status_code=status.HTTP_404_NOT_FOUND,
                    detail=f"Emloyee UUID {token_dict.selected_company.employee_uu_id} has no build with given UUID {data_dict.get('build_uu_id')}",
                )
            data_dict["build_id"] = build.id
            if data.resp_company_uu_id:
                Companies.pre_query = Companies.select_action(
                    duty_id_list=[
                        token_dict.selected_company.duty_id,
                        token_dict.selected_company.bulk_duties_id,
                    ]
                )
                company = Companies.filter_one(
                    Companies.uu_id == data.resp_company_uu_id,
                ).data
                if not company:
                    raise HTTPException(
                        status_code=status.HTTP_404_NOT_FOUND,
                        detail=f"Duty UUID {token_dict.selected_company.duty_uu_id} has no company with given UUID {data_dict.get('resp_company_uu_id')}",
                    )
                data_dict["resp_company_id"] = company.id
                data_dict["resp_company_uu_id"] = str(company.uu_id)

            decision_period_date = system_arrow.get(build.decision_period_date)
            data_dict["expiry_starts"] = system_arrow.get(
                system_arrow.now().date().year,
                int(decision_period_date.date().month),
                int(decision_period_date.date().day),
            )
            data_dict["expiry_ends"] = str(
                data_dict["expiry_starts"].shift(years=1, days=-1)
            )
            data_dict["expiry_starts"] = str(data_dict["expiry_starts"])
            build_decision_book = BuildDecisionBook.find_or_create(**data_dict)
            build_decision_book.save_and_confirm()
            return JSONResponse(
                status_code=status.HTTP_200_OK,
                content=dict(
                    message="Decision Book has created",
                    completed=True,
                    data=build_decision_book.get_dict(),
                ),
            )
        elif isinstance(token_dict, OccupantTokenObject):
            occupant_manager = OccupantTypes.filter_by_one(
                occupant_category_type="BU", occupant_code="BU-MNG"
            ).data
            if not token_dict.selected_occupant.occupant_type_id == occupant_manager.id:
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail="Only Build Manager can create decision book",
                )

            occupant_build = Build.filter_one(
                Build.id == token_dict.selected_occupant.build_id,
            ).data
            occupant_company = Companies.filter_one(
                Companies.id == token_dict.selected_occupant.responsible_company_id,
            ).data
            data_dict["build_id"] = occupant_build.id
            data_dict["build_uu_id"] = str(occupant_build.uu_id)
            data_dict["resp_company_id"] = occupant_company.id
            data_dict["resp_company_uu_id"] = str(occupant_company.uu_id)

            decision_period_date = system_arrow.get(occupant_build.decision_period_date)
            data_dict["expiry_starts"] = system_arrow.get(
                system_arrow.now().date().year,
                int(decision_period_date.date().month),
                int(decision_period_date.date().day),
            )
            data_dict["expiry_ends"] = str(
                data_dict["expiry_starts"].shift(years=1, days=-1)
            )
            data_dict["expiry_starts"] = str(data_dict["expiry_starts"])
            build_decision_book = BuildDecisionBook.find_or_create(**data_dict)
            build_decision_book.save()
            build_decision_book.update(is_confirmed=True)
            build_decision_book.save()
            return JSONResponse(
                status_code=status.HTTP_200_OK,
                content=dict(
                    message="Decision Book has created",
                    completed=True,
                    data=build_decision_book.get_dict(),
                ),
            )


class DecisionBookUpdateEventMethods(MethodToEvent):

    event_type = "UPDATE"
    __event_keys__ = {
        "6bc7035c-3b53-4c0a-8cc9-1ec9c6af1e29": "building_decision_book_update",
    }
    __event_validation__ = {"6bc7035c-3b53-4c0a-8cc9-1ec9c6af1e29": None}

    @classmethod
    def building_decision_book_update(cls, data: InsertDecisionBook, token_dict: dict):
        return


class DecisionBookPatchEventMethods(MethodToEvent):

    event_type = "PATCH"
    __event_keys__ = {
        "7b58ed84-9a65-4588-994d-30df8366b050": "building_decision_book_patch",
    }
    __event_validation__ = {"7b58ed84-9a65-4588-994d-30df8366b050": None}

    @classmethod
    def building_decision_book_patch(cls, data: InsertDecisionBook, token_dict: dict):
        return


class DecisionBookApprovalEventMethods(MethodToEvent):

    event_type = "UPDATE"
    __event_keys__ = {
        "fc745142-3437-4ca2-89fa-c5a3e2b5c6c2": "building_decision_book_approval",
    }
    __event_validation__ = {"fc745142-3437-4ca2-89fa-c5a3e2b5c6c2": None}

    @classmethod
    def building_decision_book_approval(cls, data, token_dict):
        return


DecisionBookListEventMethod = DecisionBookListEventMethods(
    action=ActionsSchema(endpoint="/build/decision_book/list")
)
DecisionBookCreateEventMethod = DecisionBookCreateEventMethods(
    action=ActionsSchema(endpoint="/build/decision_book/create")
)
DecisionBookUpdateEventMethod = DecisionBookUpdateEventMethods(
    action=ActionsSchema(endpoint="/build/decision_book/update")
)
DecisionBookPatchEventMethod = DecisionBookPatchEventMethods(
    action=ActionsSchema(endpoint="/build/decision_book/patch")
)
DecisionBookApprovalEventMethod = DecisionBookApprovalEventMethods(
    action=ActionsSchema(endpoint="/build/decision_book/approval")
)
