import math
from datetime import datetime, timedelta
from decimal import Decimal
from typing import List
from fastapi import HTTPException, status

from api_library.date_time_actions.date_functions import system_arrow, client_arrow

from sqlalchemy import (
    String,
    ForeignKey,
    Index,
    SmallInteger,
    Boolean,
    TIMESTAMP,
    Text,
    Numeric,
    Integer,
)
from sqlalchemy.orm import mapped_column, Mapped, relationship

from api_validations.validations_request import (
    InsertDecisionBook,
    InsertBuildDecisionBookItems,
    InsertBuildDecisionBookItemDebits,
    InsertBuildDecisionBookProjects,
)
from databases.sql_models.core_mixin import CrudCollection


class BuildDecisionBook(CrudCollection):
    """
    Builds class based on declarative_base and BaseMixin via session
    The start dates of the decision log periods are determined from the 'decision_period_date' field in the decision log table within the building information.
    decision_period_date = Her yıl yapılan karar toplantısı + 365 gün her yıl tekrar eden
    decision_book_pdf_path: Karar defteri pdf dosyasının yolu
    resp_company_fix_wage: Karar defterinin oluşmasını sağlayan dışardaki danışmanlık ücreti
    is_out_sourced: Karar defterinin dışardan alınan hizmetle oluşturulup oluşturulmadığı
    contact_agreement_path: Karar defterinin oluşmasını sağlayan dışardaki danışmanlık anlaşması dosyasının yolu
    contact_agreement_date: Karar defterinin oluşmasını sağlayan dışardaki danışmanlık anlaşma tarihi
    meeting_date: Karar defterinin oluşmasını sağlayan toplantı tarihi
    decision_type: Karar defterinin tipi (Bina Yönetim Toplantısı (BYT), Yıllık Acil Toplantı (YAT)
    """

    __tablename__ = "build_decision_book"
    __exclude__fields__ = []

    decision_book_pdf_path: Mapped[str] = mapped_column(
        String, server_default="", nullable=True
    )
    resp_company_fix_wage: Mapped[float] = mapped_column(
        Numeric(10, 2), server_default="0"
    )  #
    is_out_sourced: Mapped[bool] = mapped_column(Boolean, server_default="0")
    meeting_date: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True), server_default="1900-01-01"
    )
    decision_type: Mapped[str] = mapped_column(String(3), server_default="RBM")
    meeting_is_completed: Mapped[bool] = mapped_column(Boolean, server_default="0")
    meeting_completed_date: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True), nullable=True, comment="Meeting Completed Date"
    )

    build_id: Mapped[int] = mapped_column(ForeignKey("build.id"), nullable=False)
    build_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Build UUID"
    )
    resp_company_id: Mapped[int] = mapped_column(ForeignKey("companies.id"))
    resp_company_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Company UUID"
    )
    contact_id: Mapped[int] = mapped_column(
        ForeignKey("contracts.id"), nullable=True, comment="Contract id"
    )
    contact_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Contract UUID"
    )

    buildings: Mapped["Build"] = relationship(
        "Build",
        back_populates="decision_books",
        foreign_keys=build_id,
    )
    decision_book_items: Mapped[List["BuildDecisionBookItems"]] = relationship(
        "BuildDecisionBookItems",
        back_populates="decision_books",
        foreign_keys="BuildDecisionBookItems.build_decision_book_id",
    )

    __table_args__ = (
        Index("build_decision_book_ndx_011", meeting_date, build_id),
        Index("build_decision_book_ndx_011", build_id, "expiry_starts", "expiry_ends"),
        {
            "comment": "Decision Book objects that are related to decision taken at building meetings"
        },
    )

    @classmethod
    def retrieve_active_rbm(cls):
        from databases import (
            Build,
        )

        related_build = Build.find_one(id=cls.build_id)
        related_date = system_arrow.get(related_build.build_date)
        date_processed = related_date.replace(
            year=system_arrow.now().date().year, month=related_date.month, day=1
        )
        if system_arrow.now().date() <= date_processed:
            book = cls.filter_one(
                cls.expiry_ends <= date_processed,
                cls.decision_type == "RBM",
                cls.build_id == related_build.id,
            ).data
            if not book:
                cls.raise_http_exception(
                    status_code="HTTP_404_NOT_FOUND",
                    error_case="NOTFOUND",
                    message=f"Decision Book is not found for {related_build.build_name}-RBM",
                    data=dict(
                        build_id=str(related_build.uu_id),
                        build_name=related_build.build_name,
                        decision_type="RBM",
                    ),
                )
            return book
        return

    @classmethod
    def select_action(cls, duty_id, token=None):
        from databases import (
            Build,
            Companies,
        )

        related_companies = Companies.select_action(duty_id_list=[int(duty_id)])
        related_companies_ids = list(
            related_.id for related_ in related_companies.all()
        )
        related_building = Build.filter_all(Build.company_id.in_(related_companies_ids))
        related_building_ids = list(related_.id for related_ in related_building.data)
        return cls.filter_all(cls.build_id.in_(related_building_ids)).query

    @classmethod
    def create_action(cls, data: InsertDecisionBook, token=None):
        from databases import (
            Build,
            Companies,
        )

        data_dict = data.model_dump()
        if building := Build.find_one(uu_id=data.build_uu_id):
            data_dict["build_id"] = building.id
        if response_company := Companies.find_one(
            uu_id=data_dict["resp_company_uu_id"]
        ):
            data_dict["resp_company_id"] = response_company.id
        if not building:
            raise HTTPException(
                status_code=status.HTTP_406_NOT_ACCEPTABLE,
                detail="Building must be given to create decision book.",
            )
        expiry_starts = system_arrow.get(str(data_dict.get("expiry_starts"))).format(
            "%Y-%m-%d"
        )
        data_dict["expiry_starts"] = str(expiry_starts)
        expiry_ends = system_arrow.get(str(data_dict.get("expiry_ends"))).format(
            "%Y-%m-%d"
        )
        data_dict["expiry_ends"] = str(
            expiry_ends.replace(month=expiry_ends.month + 1, day=1) - timedelta(days=1)
        )

        if decision_book := BuildDecisionBook.filter_one(
            BuildDecisionBook.build_id == building.id,
            BuildDecisionBook.expiry_ends > data_dict["expiry_starts"],
            BuildDecisionBook.decision_type == data_dict.get("decision_type"),
        ).data:  # Decision book is already exist:
            cls.raise_http_exception(
                status_code=status.HTTP_409_CONFLICT,
                error_case="RECORDEXITS",
                message="Decision Book is already exist.",
                data=decision_book.get_dict(),
            )

        data_dict["expiry_starts"] = str(expiry_starts.replace(day=1))
        data_dict["expiry_ends"] = str(
            expiry_ends.replace(month=expiry_ends.month + 1, day=1) - timedelta(days=1)
        )
        del data_dict["build_uu_id"], data_dict["resp_company_uu_id"]
        return cls.find_or_create(**data_dict)

    @property
    def semester(self):
        start_format = "".join(
            [str(self.expiry_starts.year), "-", str(self.expiry_starts.month)]
        )
        end_format = "".join(
            [str(self.expiry_ends.year), "-", str(self.expiry_ends.month)]
        )
        return "".join([start_format, " ", end_format])

    def check_book_is_valid(self, bank_date: str):
        if all(
            [True if letter in str(bank_date) else False for letter in ["-", " ", ":"]]
        ):
            bank_date = datetime.strptime(str(bank_date), "%Y-%m-%d %H:%M:%S")
        date_valid = (
            system_arrow.get(self.expiry_starts)
            < system_arrow.get(bank_date)
            < system_arrow.get(self.expiry_ends)
        )
        return date_valid and self.active and not self.deleted

    @classmethod
    def retrieve_valid_book(cls, bank_date, iban):
        from databases import (
            BuildIbans,
        )

        if all(
            [True if letter in str(bank_date) else False for letter in ["-", " ", ":"]]
        ):
            bank_date = datetime.strptime(str(bank_date), "%Y-%m-%d %H:%M:%S")
            build_iban = BuildIbans.find_one(iban=iban)
            decision_book: cls = cls.filter_one(
                cls.build_id == build_iban.build_id,
                cls.expiry_starts < bank_date,
                cls.expiry_ends > bank_date,
                cls.active == True,
                cls.deleted == False,
            ).data
            decision_book.check_book_is_valid(bank_date.__str__())
            return decision_book
        return


class BuildDecisionBookInvitations(CrudCollection):
    """
    Builds class based on declarative_base and BaseMixin via session
    """

    __tablename__ = "build_decision_book_invitations"
    __exclude__fields__ = []

    build_id: Mapped[int] = mapped_column(Integer, nullable=False)
    build_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Build UUID"
    )
    decision_book_id: Mapped[int] = mapped_column(
        ForeignKey("build_decision_book.id"), nullable=False
    )
    decision_book_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Decision Book UUID"
    )

    invitation_type: Mapped[str] = mapped_column(
        String, nullable=False, comment="Invite Type"
    )
    invitation_attempt: Mapped[int] = mapped_column(SmallInteger, server_default="1")
    living_part_count: Mapped[int] = mapped_column(SmallInteger, server_default="1")
    living_part_percentage: Mapped[float] = mapped_column(
        Numeric(10, 2), server_default="0.51"
    )

    message: Mapped[str] = mapped_column(
        Text, nullable=True, comment="Invitation Message"
    )
    planned_date: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True), nullable=False, comment="Planned Meeting Date"
    )
    planned_date_expires: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True), nullable=False, comment="Planned Meeting Date Expires"
    )

    __table_args__ = (
        Index(
            "_build_decision_book_invitations_ndx_01",
            invitation_type,
            planned_date,
            invitation_attempt,
            unique=True,
        ),
        {"comment": "People that are invited to building meetings."},
    )

    @classmethod
    def check_invites_are_ready_for_meeting(cls, selected_decision_book, token_dict):
        first_book_invitation = BuildDecisionBookInvitations.filter_one(
            BuildDecisionBookInvitations.build_id
            == token_dict.selected_occupant.build_id,
            BuildDecisionBookInvitations.decision_book_id == selected_decision_book.id,
            BuildDecisionBookInvitations.invitation_attempt == 1,
        ).data
        if not first_book_invitation:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"First Meeting Invitation is not found for Decision Book UUID : {selected_decision_book.uu_id}",
            )
        need_attend_count = int(first_book_invitation.living_part_count) * Decimal(
            first_book_invitation.living_part_percentage
        )
        valid_invite_count = (
            BuildDecisionBookPerson.filter_all(
                BuildDecisionBookPerson.invite_id == first_book_invitation.id,
                BuildDecisionBookPerson.build_decision_book_id
                == selected_decision_book.id,
                BuildDecisionBookPerson.is_attending == True,
                system=True,
            )
            .query.distinct(BuildDecisionBookPerson.person_id)
            .count()
        )

        second_book_invitation = BuildDecisionBookInvitations.filter_one(
            BuildDecisionBookInvitations.build_id
            == token_dict.selected_occupant.build_id,
            BuildDecisionBookInvitations.decision_book_id == selected_decision_book.id,
            BuildDecisionBookInvitations.invitation_attempt == 2,
            system=True,
        ).data
        if not valid_invite_count >= need_attend_count and not second_book_invitation:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"In order meeting to be held, {math.ceil(need_attend_count)} people must attend "
                f"to the meeting. Only {valid_invite_count} people are attending to the meeting.",
            )
        return first_book_invitation or second_book_invitation


class BuildDecisionBookPerson(CrudCollection):
    """
    Builds class based on declarative_base and BaseMixin via session
    Karar Defteri toplantılarına katılan kişiler veya yetkililer
    dues_percent_discount: Katılımcının aidat indirim oranı  Aidatdan yüzde indirim alır
    dues_fix_discount: Katılımcının aidat sabit miktarı  Aidatdan sabit bir miktar indirim alır
    dues_discount_approval_date: Bu kişinin indiriminin onayladığı tarih
    management_typecode: Kişinin toplantı görevi
    """

    __tablename__ = "build_decision_book_person"
    __exclude__fields__ = []
    __enum_list__ = [("management_typecode", "BuildManagementType", "bm")]

    dues_percent_discount: Mapped[int] = mapped_column(SmallInteger, server_default="0")
    dues_fix_discount: Mapped[float] = mapped_column(Numeric(10, 2), server_default="0")
    dues_discount_approval_date: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True), server_default="1900-01-01 00:00:00"
    )
    send_date: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True), nullable=False, comment="Confirmation Date"
    )
    is_attending: Mapped[bool] = mapped_column(
        Boolean, server_default="0", comment="Occupant is Attending to invitation"
    )
    confirmed_date: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True), nullable=True, comment="Confirmation Date"
    )
    token: Mapped[str] = mapped_column(
        String, server_default="", comment="Invitation Token"
    )

    vicarious_person_id: Mapped[int] = mapped_column(
        ForeignKey("people.id"), nullable=True, comment="Vicarious Person ID"
    )
    vicarious_person_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Vicarious Person UUID"
    )

    invite_id: Mapped[int] = mapped_column(
        ForeignKey("build_decision_book_invitations.id"), nullable=False
    )
    invite_uu_id: Mapped[str] = mapped_column(
        String, nullable=False, comment="Invite UUID"
    )

    build_decision_book_id: Mapped[int] = mapped_column(
        ForeignKey("build_decision_book.id"), nullable=False
    )
    build_decision_book_uu_id: Mapped[str] = mapped_column(
        String, nullable=False, comment="Decision Book UUID"
    )
    build_living_space_id: Mapped[int] = mapped_column(
        ForeignKey("build_living_space.id"), nullable=False
    )
    build_living_space_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Living Space UUID"
    )
    person_id: Mapped[int] = mapped_column(ForeignKey("people.id"), nullable=False)
    # person_uu_id: Mapped[str] = mapped_column(String, nullable=False, comment="Person UUID")

    __table_args__ = (
        Index(
            "_build_decision_book_person_ndx_01",
            build_decision_book_id,
            invite_id,
            build_living_space_id,
            unique=True,
        ),
        {"comment": "People that are attended to building meetings."},
    )

    def retrieve_all_occupant_types(self):
        all_decision_book_people = self.filter_all(
            BuildDecisionBookPersonOccupants.invite_id == self.invite_id,
            system=True,
        )
        BuildDecisionBookPersonOccupants.pre_query = all_decision_book_people.query
        return BuildDecisionBookPersonOccupants.filter_all(system=True).data

    def add_occupant_type(self, occupant_type, build_living_space_id: int = None):
        from databases import (
            Build,
            BuildLivingSpace,
            Services,
        )
        from api_events.events.events.events_bind_services import (
            ServiceBindOccupantEventMethods,
        )

        book_dict = dict(
            build_decision_book_person_id=self.id,
            build_decision_book_person_uu_id=str(self.uu_id),
            invite_id=self.invite_id,
            invite_uu_id=str(self.invite_uu_id),
            occupant_type_id=occupant_type.id,
            occupant_type_uu_id=str(occupant_type.uu_id),
        )
        if person_occupants := BuildDecisionBookPersonOccupants.find_or_create(
            **book_dict
        ):
            person_occupants.save_and_confirm()

            decision_book = BuildDecisionBook.filter_one(
                BuildDecisionBook.id == self.build_decision_book_id,
            ).data
            person_occupants.update(
                expiry_starts=decision_book.expiry_starts,
                expiry_ends=decision_book.expiry_ends,
            )
            if build_living_space_id:
                related_service = Services.filter_by_one(
                    related_responsibility=str(occupant_type.occupant_code),
                    **Services.valid_record_dict,
                ).data
                if not related_service:
                    raise HTTPException(
                        status_code=status.HTTP_404_NOT_FOUND,
                        detail=f"Service is not found for {occupant_type.occupant_code}",
                    )

                decision_build = Build.filter_one(
                    Build.id == decision_book.build_id,
                ).data
                management_room = decision_build.management_room
                if not management_room:
                    raise HTTPException(
                        status_code=status.HTTP_404_NOT_FOUND,
                        detail=f"Management Room is not found in {decision_build.build_name}",
                    )

                living_space = BuildLivingSpace.filter_one(
                    BuildLivingSpace.id == build_living_space_id,
                ).data
                expiry_ends = str(
                    system_arrow.get(decision_book.meeting_date).shift(hours=23)
                )
                expiry_starts = str(system_arrow.get(decision_book.meeting_date))
                related_living_space = BuildLivingSpace.find_or_create(
                    build_parts_id=management_room.id,
                    build_parts_uu_id=str(management_room.uu_id),
                    occupant_type=occupant_type.id,
                    occupant_type_uu_id=str(occupant_type.uu_id),
                    person_id=living_space.person_id,
                    person_uu_id=str(living_space.person_uu_id),
                    expiry_starts=expiry_starts,
                    expiry_ends=expiry_ends,
                )
                expires_at = str(
                    system_arrow.get(decision_book.meeting_date).shift(days=15)
                )
                related_living_space.save_and_confirm()
                ServiceBindOccupantEventMethods.bind_services_occupant_system(
                    build_living_space_id=related_living_space.id,
                    service_id=related_service.id,
                    expires_at=expires_at,
                )
            return person_occupants
        return

    def get_occupant_types(self):
        if occupants := BuildDecisionBookPersonOccupants.filter_all(
            BuildDecisionBookPersonOccupants.build_decision_book_person_id == self.id,
        ).data:
            return occupants
        return

    def check_occupant_type(self, occupant_type):
        book_person_occupant_type = BuildDecisionBookPersonOccupants.filter_one(
            BuildDecisionBookPersonOccupants.build_decision_book_person_id == self.id,
            BuildDecisionBookPersonOccupants.occupant_type_id == occupant_type.id,
            BuildDecisionBookPersonOccupants.active == True,
            BuildDecisionBookPersonOccupants.is_confirmed == True,
        ).data
        if not book_person_occupant_type:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"Occupant Type : {occupant_type.occupant_code} is not found in "
                f"Decision Book Person UUID {self.uu_id}",
            )


class BuildDecisionBookPersonOccupants(CrudCollection):
    """
    Builds class based on declarative_base and BaseMixin via session
    """

    __tablename__ = "build_decision_book_person_occupants"
    __exclude__fields__ = []

    build_decision_book_person_id: Mapped[int] = mapped_column(
        ForeignKey("build_decision_book_person.id"), nullable=False
    )
    build_decision_book_person_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Decision Book Person UUID"
    )
    invite_id: Mapped[int] = mapped_column(
        ForeignKey("build_decision_book_invitations.id"), nullable=True
    )
    invite_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Invite UUID"
    )

    occupant_type_id: Mapped[int] = mapped_column(
        ForeignKey("occupant_types.id"), nullable=False
    )
    occupant_type_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Occupant UUID"
    )

    __table_args__ = (
        Index(
            "_build_decision_book_person_occupants_ndx_01",
            build_decision_book_person_id,
            occupant_type_id,
            unique=True,
        ),
        {"comment": "Occupant Types of People that are attended to building meetings."},
    )


class BuildDecisionBookItems(CrudCollection):
    """
    Builds class based on declarative_base and BaseMixin via session
    item_commentary = metine itiraz şerh maddesi için
    item_order = maddelerin sıralanma numarası
    item_objection = maddelerin itiraz şerhi Text şeklinde
    """

    __tablename__ = "build_decision_book_items"
    __exclude__fields__ = []

    item_order: Mapped[int] = mapped_column(
        SmallInteger, nullable=False, comment="Order Number of Item"
    )
    item_comment: Mapped[str] = mapped_column(
        Text, nullable=False, comment="Comment Content"
    )
    item_objection: Mapped[str] = mapped_column(
        Text, nullable=True, comment="Objection Content"
    )
    info_is_completed: Mapped[bool] = mapped_column(
        Boolean, server_default="0", comment="Info process is Completed"
    )
    is_payment_created: Mapped[bool] = mapped_column(
        Boolean, server_default="0", comment="Are payment Records Created"
    )

    info_type_id: Mapped[int] = mapped_column(
        ForeignKey("api_enum_dropdown.id"), nullable=True
    )
    info_type_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Info Type UUID"
    )

    build_decision_book_id: Mapped[int] = mapped_column(
        ForeignKey("build_decision_book.id"), nullable=False
    )
    build_decision_book_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Decision Book UUID"
    )
    item_short_comment: Mapped[str] = mapped_column(
        String(24),
        nullable=True,
        comment="This field is reserved for use in grouping data or in the pivot heading.",
    )

    decision_books: Mapped["BuildDecisionBook"] = relationship(
        "BuildDecisionBook",
        back_populates="decision_book_items",
        foreign_keys=[build_decision_book_id],
    )
    decision_book_project: Mapped["BuildDecisionBookProjects"] = relationship(
        "BuildDecisionBookProjects",
        back_populates="build_decision_book_item",
        foreign_keys="BuildDecisionBookProjects.build_decision_book_item_id",
    )

    __table_args__ = (
        Index("_build_decision_book_item_ndx_01", build_decision_book_id),
        Index(
            "_build_decision_book_item_ndx_02",
            build_decision_book_id,
            item_order,
            unique=True,
        ),
        {
            "comment": "Decision Book Items that are related to decision taken at building meetings"
        },
    )

    @classmethod
    def select_action(cls, duty_id, token=None):
        from databases import (
            Build,
            Companies,
        )

        related_companies = Companies.select_action(duty_id_list=[duty_id])
        related_companies_ids = list(
            related_.id for related_ in related_companies.all()
        )
        related_building = Build.query.filter(
            Build.company_id.in_(related_companies_ids)
        )
        related_building_ids = list(related_.id for related_ in related_building.all())
        related_decision_books = BuildDecisionBook.query.filter(
            BuildDecisionBook.build_id.in_(related_building_ids)
        )
        related_decision_books_ids = list(
            related_.id for related_ in related_decision_books.all()
        )
        return cls.query.filter(
            cls.build_decision_book_id.in_(related_decision_books_ids)
        )

    @classmethod
    def create_action(cls, data: InsertBuildDecisionBookItems, token):
        data_dict = data.dump()
        BuildDecisionBook.pre_query = BuildDecisionBook.select_action(
            duty_id=token.duty_list["duty_id"]
        )
        cls.pre_query = cls.select_action(duty_id=token.duty_list["duty_id"])
        if decision_book := BuildDecisionBook.filter_one(
            BuildDecisionBook.uu_id == data.build_decision_book_uu_id
        ).data:
            found_dict = dict(
                item_order=data.item_order, build_decision_book_id=decision_book.id
            )
            if decision_book_is_already := cls.find_one(**found_dict):
                decision_book_is_already.is_found = True
                return decision_book_is_already.get_dict()
            data_dict["build_decision_book_id"] = decision_book.id
            data_dict["is_confirmed"] = True
            del data_dict["build_decision_book_uu_id"]
            return BuildDecisionBookItems.find_or_create(**data_dict)

    @classmethod
    def check_meeting_is_valid_to_start_add_attendance(cls, decision_book, token_dict):
        from databases import (
            People,
            OccupantTypes,
        )

        active_invite = (
            BuildDecisionBookInvitations.check_invites_are_ready_for_meeting(
                selected_decision_book=decision_book,
                token_dict=token_dict,
            )
        )
        occupant_type_required_list = ("MT-PRS", "MT-WRT", "BU-MNG", "BU-SPV")
        occupant_type_list = OccupantTypes.filter_all(
            OccupantTypes.occupant_code.in_(occupant_type_required_list),
            system=True,
        ).data
        # active_invite = invitations[1] if invitations[1] else invitations[0]
        invitation = BuildDecisionBookInvitations.filter_one(
            BuildDecisionBookInvitations.id == active_invite.id
        ).data
        people_book_attend_count = None
        if int(invitation.invitation_attempt) == 1:
            people_book_attend_is_attending = BuildDecisionBookPerson.filter_all(
                BuildDecisionBookPerson.invite_id == invitation.id,
                BuildDecisionBookPerson.is_attending == True,
            )
            people_book_attend = BuildDecisionBookPersonOccupants.filter_all(
                BuildDecisionBookPersonOccupants.build_decision_book_person_id.in_(
                    [person.id for person in people_book_attend_is_attending.data]
                ),
                BuildDecisionBookPersonOccupants.occupant_type_id.in_(
                    [occupant_type.id for occupant_type in occupant_type_list]
                ),
            )
            people_book_attend_count = people_book_attend.count
            if not people_book_attend_count == len(occupant_type_required_list) - 1:
                error_detail = " - ".join(occupant_type_required_list)
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail=f"{error_detail} occupant types must be attend to meeting. "
                    f"Check attendants and try again",
                )

        comment = (
            lambda id_, occ_type, full_name: f"{full_name} is nomindated for {occ_type} at Meeting Invite Code : {id_}"
        )
        book_items_dict = dict(
            build_decision_book_id=decision_book.id,
            build_decision_book_uu_id=str(decision_book.uu_id),
            is_confirmed=True,
            active=True,
            is_payment_created=True,
        )
        occupant_type_pre = OccupantTypes.filter_by_one(
            system=True, occupant_code="MT-PRS", occupant_category_type="MT"
        ).data
        occupant_type_wrt = OccupantTypes.filter_by_one(
            system=True, occupant_code="MT-WRT", occupant_category_type="MT"
        ).data
        occupant_type_mng = OccupantTypes.filter_by_one(
            system=True, occupant_code="BU-MNG", occupant_category_type="BU"
        ).data

        person_occupants_pre = BuildDecisionBookPersonOccupants.filter_one(
            BuildDecisionBookPersonOccupants.invite_id == invitation.id,
            BuildDecisionBookPersonOccupants.occupant_type_id == occupant_type_pre.id,
        ).data
        person_invite_pret = BuildDecisionBookPerson.filter_one(
            BuildDecisionBookPerson.id
            == person_occupants_pre.build_decision_book_person_id
        ).data
        person = People.filter_one(People.id == person_invite_pret.person_id).data
        created_attendance = BuildDecisionBookItems.find_or_create(
            **book_items_dict,
            item_order=1,
            item_comment=comment(
                id_=person_invite_pret.invite_uu_id,
                occ_type=occupant_type_pre.occupant_type,
                full_name=person.full_name,
            ),
        )
        created_attendance.save_and_confirm()

        person_occupants_wrt = BuildDecisionBookPersonOccupants.filter_one(
            BuildDecisionBookPersonOccupants.invite_id == invitation.id,
            BuildDecisionBookPersonOccupants.occupant_type_id == occupant_type_wrt.id,
        ).data
        person_invite_wrt = BuildDecisionBookPerson.filter_one(
            BuildDecisionBookPerson.id
            == person_occupants_wrt.build_decision_book_person_id
        ).data
        person = People.filter_one(People.id == person_invite_pret.person_id).data
        created_attendance = BuildDecisionBookItems.find_or_create(
            **book_items_dict,
            item_order=2,
            item_comment=comment(
                id_=person_invite_wrt.invite_uu_id,
                occ_type=occupant_type_wrt.occupant_type,
                full_name=person.full_name,
            ),
        )
        created_attendance.save_and_confirm()

        person_occupants_mng = BuildDecisionBookPersonOccupants.filter_one(
            BuildDecisionBookPersonOccupants.invite_id == invitation.id,
            BuildDecisionBookPersonOccupants.occupant_type_id == occupant_type_mng.id,
        ).data
        person_invite_mng = BuildDecisionBookPerson.filter_one(
            BuildDecisionBookPerson.id
            == person_occupants_mng.build_decision_book_person_id
        ).data
        person = People.filter_one(People.id == person_invite_pret.person_id).data
        created_attendance = BuildDecisionBookItems.find_or_create(
            **book_items_dict,
            item_order=3,
            item_comment=comment(
                id_=person_invite_mng.invite_uu_id,
                occ_type=occupant_type_mng.occupant_type,
                full_name=person.full_name,
            ),
        )
        created_attendance.save_and_confirm()
        return people_book_attend_count


class BuildDecisionBookItemsUnapproved(CrudCollection):
    """
    Builds class based on declarative_base and BaseMixin via session unapproved personnel
    """

    __tablename__ = "build_decision_book_items_unapproved"
    __exclude__fields__ = []

    item_objection: Mapped[str] = mapped_column(
        Text, nullable=False, comment="Objection Content"
    )
    item_order: Mapped[int] = mapped_column(
        SmallInteger, nullable=False, comment="Order Number"
    )

    decision_book_item_id: Mapped[int] = mapped_column(
        ForeignKey("build_decision_book_items.id"), nullable=False
    )
    decision_book_item_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Decision Book Item"
    )
    person_id: Mapped[int] = mapped_column(ForeignKey("people.id"), nullable=False)
    person_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Person UUID"
    )
    build_decision_book_item: Mapped[int] = mapped_column(
        ForeignKey("build_decision_book_items.id"), nullable=False
    )
    build_decision_book_item_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Decision Book Item UUID"
    )

    __table_args__ = (
        Index("_build_decision_book_item_unapproved_ndx_01", build_decision_book_item),
        {
            "comment": "People that are unapproved partially or completely in decision book items"
        },
    )


class BuildDecisionBookPayments(CrudCollection):
    """
    Builds class based on declarative_base and BaseMixin via session
    period_time = to_char(NEW.process_date, 'YYYY-MM');
    """

    __tablename__ = "build_decision_book_payments"
    __exclude__fields__ = []
    __enum_list__ = [("receive_debit", "DebitTypes", "D")]

    payment_plan_time_periods: Mapped[str] = mapped_column(
        String(10), nullable=False, comment="Payment Plan Time Periods"
    )
    process_date: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True), nullable=False, comment="Payment Due Date"
    )
    payment_amount: Mapped[float] = mapped_column(
        Numeric(16, 2), nullable=False, comment="Payment Amount"
    )
    currency: Mapped[str] = mapped_column(String(8), server_default="TRY")

    payment_types_id: Mapped[int] = mapped_column(
        ForeignKey("api_enum_dropdown.id"), nullable=True
    )
    payment_types_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Dues Type UUID"
    )

    period_time: Mapped[str] = mapped_column(String(12))
    process_date_y: Mapped[int] = mapped_column(SmallInteger)
    process_date_m: Mapped[int] = mapped_column(SmallInteger)

    build_decision_book_item_id: Mapped[int] = mapped_column(
        ForeignKey("build_decision_book_items.id"),
        nullable=False,
        comment="Build Decision Book Item ID",
    )
    build_decision_book_item_uu_id: Mapped[str] = mapped_column(
        String, nullable=False, comment="Decision Book Item UUID"
    )
    build_parts_id: Mapped[int] = mapped_column(
        ForeignKey("build_parts.id"), nullable=False
    )
    build_parts_uu_id: Mapped[str] = mapped_column(
        String, nullable=False, comment="Build Part UUID"
    )
    decision_book_project_id: Mapped[int] = mapped_column(
        ForeignKey("build_decision_book_projects.id"),
        nullable=True,
        comment="Decision Book Project ID",
    )
    decision_book_project_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Decision Book Project UUID"
    )
    account_records_id: Mapped[int] = mapped_column(
        ForeignKey("account_records.id"), nullable=True
    )
    account_records_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Account Record UU ID"
    )

    # budget_records_id: Mapped[int] = mapped_column(ForeignKey("account_records.id"), nullable=True)
    # budget_records_uu_id: Mapped[str] = mapped_column(
    #     String, nullable=True, comment="Budget UUID"
    # )
    # accounting_id: Mapped[int] = mapped_column(ForeignKey("account_detail.id"), nullable=True)
    # accounting_uu_id: Mapped[str] = mapped_column(
    #     String, nullable=True, comment="Accounting UUID"
    # )
    # receive_debit_id: Mapped[int] = mapped_column(ForeignKey("api_enum_dropdown.id"), nullable=True)
    # receive_debit_uu_id: Mapped[str] = mapped_column(String, nullable=True, comment="Debit UUID")

    # accounting: Mapped["AccountDetail"] = relationship(
    #     "AccountDetail",
    #     back_populates="decision_book_payment_detail",
    #     foreign_keys=[accounting_id],
    # )
    #
    # decision_book_master: Mapped["BuildDecisionBookPaymentsMaster"] = relationship(
    #     "BuildDecisionBookPaymentsMaster",
    #     back_populates="decision_book_payment_detail",
    #     foreign_keys=[build_decision_book_payments_master_id],
    # )
    # budget_records: Mapped["CompanyBudgetRecords"] = relationship(
    #     "CompanyBudgetRecords",
    #     back_populates="decision_book_payment_detail",
    #     foreign_keys=[budget_records_id],
    # )

    __table_args__ = (
        Index(
            "build_decision_book_payments_detail_ndx_00",
            build_decision_book_item_id,
            build_parts_id,
            payment_plan_time_periods,
            process_date,
            payment_types_id,
            account_records_id,
            unique=True,
        ),
        Index("build_decision_book_payments_detail_ndx_01", account_records_id),
        {"comment": "Payment Details of Decision Book Payments"},
    )


class BuildDecisionBookLegal(CrudCollection):
    """
    Builds class based on declarative_base and BaseMixin via session
    lawsuits_type C:Court Mehkeme M: mediator arabulucu
    """

    __tablename__ = "build_decision_book_legal"
    __exclude__fields__ = []

    period_start_date: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True), nullable=False, comment="Start Date of Legal Period"
    )
    lawsuits_decision_number: Mapped[str] = mapped_column(
        String, nullable=False, comment="Lawsuits Decision Number"
    )
    lawsuits_decision_date: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True), nullable=False, comment="Lawsuits Decision Date"
    )

    period_stop_date: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True), server_default="2099-12-31 23:59:59"
    )
    decision_book_pdf_path: Mapped[str] = mapped_column(
        String, server_default="", nullable=True
    )
    resp_company_total_wage: Mapped[float] = mapped_column(
        Numeric(10, 2), server_default="0", nullable=True
    )
    contact_agreement_path: Mapped[str] = mapped_column(
        String, server_default="", nullable=True
    )
    contact_agreement_date: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True), server_default="1900-01-01 00:00:00", nullable=True
    )
    meeting_date: Mapped[str] = mapped_column(
        TIMESTAMP(timezone=True), server_default="1900-01-01 00:00:00"
    )
    lawsuits_type: Mapped[str] = mapped_column(String(1), server_default="C")
    lawsuits_name: Mapped[str] = mapped_column(String(128))
    lawsuits_note: Mapped[str] = mapped_column(String(512))
    lawyer_cost: Mapped[float] = mapped_column(Numeric(20, 2))
    mediator_lawyer_cost: Mapped[float] = mapped_column(Numeric(20, 2))
    other_cost: Mapped[float] = mapped_column(Numeric(20, 2))
    legal_cost: Mapped[float] = mapped_column(Numeric(20, 2))
    approved_cost: Mapped[float] = mapped_column(Numeric(20, 2))
    total_price: Mapped[float] = mapped_column(Numeric(20, 2))

    build_db_item_id: Mapped[int] = mapped_column(
        ForeignKey("build_decision_book_items.id"), nullable=False
    )
    build_db_item_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Decision Book Item UUID"
    )
    resp_attorney_id: Mapped[int] = mapped_column(
        ForeignKey("people.id"), nullable=False
    )
    resp_attorney_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Attorney UUID"
    )
    resp_attorney_company_id: Mapped[int] = mapped_column(ForeignKey("companies.id"))
    resp_attorney_company_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Company UUID"
    )
    mediator_lawyer_person_id: Mapped[int] = mapped_column(ForeignKey("people.id"))
    mediator_lawyer_person_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Mediator Lawyer UUID"
    )

    __table_args__ = (
        Index("_build_decision_book_legal_ndx_00", meeting_date),
        {
            "comment": "Legal items related to decision book items recoreded at building meetings"
        },
    )


class BuildDecisionBookProjects(CrudCollection):
    """
    Builds class based on declarative_base and BaseMixin via session
    project_type = C:Court Mehkeme M: mediator arabulucu
    """

    __tablename__ = "build_decision_book_projects"
    __exclude__fields__ = []

    project_no: Mapped[str] = mapped_column(
        String(12), nullable=True, comment="Project Number of Decision Book"
    )
    project_name: Mapped[str] = mapped_column(
        String, nullable=False, comment="Project Name"
    )
    project_start_date: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True), nullable=False, comment="Project Start Date"
    )
    project_stop_date: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True), server_default="2099-12-31 23:59:59"
    )
    project_type: Mapped[str] = mapped_column(String, server_default="C")
    project_note: Mapped[str] = mapped_column(Text)

    decision_book_pdf_path: Mapped[str] = mapped_column(
        String, server_default="", nullable=True
    )
    is_completed: Mapped[bool] = mapped_column(
        Boolean, server_default="0", comment="Project is Completed"
    )
    status_code: Mapped[int] = mapped_column(SmallInteger, nullable=True)
    resp_company_fix_wage: Mapped[float] = mapped_column(
        Numeric(10, 2), server_default="0"
    )
    is_out_sourced: Mapped[bool] = mapped_column(Boolean, server_default="0")

    meeting_date: Mapped[TIMESTAMP] = mapped_column(
        TIMESTAMP(timezone=True), server_default="1900-01-01 00:00:00", index=True
    )
    currency: Mapped[str] = mapped_column(String(8), server_default="TRY")
    bid_price: Mapped[float] = mapped_column(Numeric(16, 4), server_default="0")
    approved_price: Mapped[float] = mapped_column(Numeric(16, 4), server_default="0")
    final_price: Mapped[float] = mapped_column(Numeric(16, 4), server_default="0")

    contact_id: Mapped[int] = mapped_column(
        ForeignKey("contracts.id"), nullable=True, comment="Contract id"
    )
    contact_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Contract UUID"
    )
    build_decision_book_id: Mapped[int] = mapped_column(
        ForeignKey("build_decision_book.id"), nullable=False
    )
    build_decision_book_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Decision Book UUID"
    )
    build_decision_book_item_id: Mapped[int] = mapped_column(
        ForeignKey("build_decision_book_items.id"), nullable=False
    )
    build_decision_book_item_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Decision Book Item UUID"
    )
    project_response_living_space_id: Mapped[int] = mapped_column(
        ForeignKey("build_living_space.id"),
        nullable=True,
        comment="Project Response Person ID",
    )
    project_response_living_space_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Project Response Person UUID"
    )
    resp_company_id: Mapped[int] = mapped_column(
        ForeignKey("companies.id"), nullable=True
    )
    resp_company_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Company UUID"
    )

    build_decision_book_item: Mapped["BuildDecisionBookItems"] = relationship(
        "BuildDecisionBookItems",
        back_populates="decision_book_project",
        foreign_keys=[build_decision_book_item_id],
    )

    @classmethod
    def select_action(cls, duty_id, token=None):
        from databases import (
            Build,
            Companies,
        )

        related_companies = Companies.select_action(duty_id_list=[duty_id])
        related_companies_ids = list(
            related_.id for related_ in related_companies.all()
        )
        related_building = Build.filter_all(Build.company_id.in_(related_companies_ids))
        related_building_ids = list(related_.id for related_ in related_building.data)
        related_decision_books = BuildDecisionBook.filter_all(
            BuildDecisionBook.build_id.in_(related_building_ids),
        ).data
        related_decision_books_ids = list(
            related_.id for related_ in related_decision_books
        )
        related_decision_books_items = BuildDecisionBookItems.filter_all(
            BuildDecisionBookItems.build_decision_book_id.in_(
                related_decision_books_ids
            ),
        ).data
        related_decision_books_items_ids = list(
            related_.id for related_ in related_decision_books_items
        )
        return cls.filter_all(
            cls.build_decision_book_item_id.in_(related_decision_books_items_ids),
        ).query

    @classmethod
    def create_action(cls, data: InsertBuildDecisionBookProjects, token=None):
        from databases import (
            People,
            Companies,
        )

        data_dict = data.dump()
        BuildDecisionBookItems.pre_query = BuildDecisionBookItems.select_action(
            duty_id=token.duty_list["duty_id"]
        )
        People.pre_query = People.select_action(
            duty_id_list=[token.duty_list["duty_id"]]
        )
        decision_book_project_item = BuildDecisionBookItems.find_one_or_abort(
            uu_id=data_dict.get("build_decision_book_item_uu_id")
        )
        project_response_person = People.find_one_or_abort(
            uu_id=data_dict.get("project_response_person_uu_id")
        )
        data_dict["build_decision_book_item_id"] = decision_book_project_item.id
        data_dict["project_response_person_id"] = project_response_person.id
        if data.resp_company_uu_id:
            resp_company = Companies.find_one(uu_id=data.resp_company_uu_id)
            data_dict["resp_company_id"] = resp_company.id
        del (
            data_dict["build_decision_book_item_uu_id"],
            data_dict["project_response_person_uu_id"],
        )
        del data_dict["resp_company_uu_id"]
        data_dict["is_confirmed"] = True
        return cls.find_or_create(**data_dict)

    __table_args__ = (
        Index(
            "_build_decision_book_project_ndx_00",
            project_no,
            project_start_date,
            unique=True,
        ),
        {
            "comment": "Project related to decision taken at building meetings on book items"
        },
    )

    @property
    def get_project_year(self):
        return self.decision_book_items.decision_books.period_start_date.year

    @property
    def get_project_no(self):
        return f"{self.get_project_year}-{str(self.id)[-4:].zfill(4)}"


class BuildDecisionBookProjectPerson(CrudCollection):
    """
    Builds class based on declarative_base and BaseMixin via session
    """

    __tablename__ = "build_decision_book_project_person"
    __exclude__fields__ = []
    # __enum_list__ = [("management_typecode", "ProjectTeamTypes", "PTT-EMP")]

    dues_percent_discount: Mapped[int] = mapped_column(SmallInteger, server_default="0")
    job_fix_wage: Mapped[float] = mapped_column(Numeric(10, 2), server_default="0")
    bid_price: Mapped[float] = mapped_column(Numeric(10, 2), server_default="0")
    decision_price: Mapped[float] = mapped_column(Numeric(10, 2), server_default="0")

    build_decision_book_project_id: Mapped[int] = mapped_column(
        ForeignKey("build_decision_book_projects.id"), nullable=False
    )
    build_decision_book_project_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Decision Book Project UUID"
    )
    living_space_id: Mapped[int] = mapped_column(
        ForeignKey("build_living_space.id"), nullable=False
    )
    living_space_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Living Space UUID"
    )

    __table_args__ = (
        {"comment": "People that are attended to building project meetings."},
    )


class BuildDecisionBookProjectItems(CrudCollection):
    """
    Builds class based on declarative_base and BaseMixin via session
    """

    __tablename__ = "build_decision_book_project_items"
    __exclude__fields__ = []

    item_header: Mapped[str] = mapped_column(
        String, nullable=False, comment="Item Header"
    )
    item_comment: Mapped[str] = mapped_column(
        Text, nullable=False, comment="Item Comment"
    )
    attachment_pdf_path: Mapped[str] = mapped_column(
        String, server_default="", nullable=True, comment="Attachment PDF Path"
    )
    item_estimated_cost: Mapped[float] = mapped_column(
        Numeric(16, 2), server_default="0", comment="Estimated Cost"
    )
    item_short_comment: Mapped[str] = mapped_column(
        String(24),
        nullable=True,
        comment="This field is reserved for use in grouping data or in the pivot heading.",
    )

    build_decision_book_project_id: Mapped[int] = mapped_column(
        ForeignKey("build_decision_book_projects.id"), nullable=False
    )
    build_decision_book_project_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Decision Book Project UUID"
    )

    __table_args__ = (
        {"comment": "Project Items related to decision taken at building meetings"},
    )


#
# class BuildDecisionBookPaymentsMaster(CrudCollection):
#     """
#     Builds class based on declarative_base and BaseMixin via session
#     """
#
#     __tablename__ = "build_decision_book_payments_master"
#     __exclude__fields__ = []
#     __enum_list__ = [("dues_types", "BuildDuesTypes", "D")]
#
#     payment_plan_time_periods = mapped_column(
#         String(8), nullable=False, comment="Payment Plan Time Periods"
#     )
#     default_payment_amount = mapped_column(
#         Numeric(20, 2), nullable=False, comment="Default Payment Amount"
#     )
#
#     dues_types_id: Mapped[int] = mapped_column(ForeignKey("api_enum_dropdown.id"), nullable=True)
#     dues_types_uu_id = mapped_column(String, nullable=True, comment="Dues Type UUID")
#     build_decision_book_item_debits_id = mapped_column(
#         ForeignKey("build_decision_book_item_debits.id"), nullable=False
#     )
#     build_decision_book_item_debits_uu_id = mapped_column(
#         String, nullable=True, comment="Decision Book Item Debit UUID"
#     )
#     build_parts_id: Mapped[int] = mapped_column(ForeignKey("build_parts.id"), nullable=False)
#     build_parts_uu_id = mapped_column(String, nullable=True, comment="Build Part UUID")
#
#     # decision_books_item_debits: Mapped["BuildDecisionBookItemDebits"] = relationship(
#     #     "BuildDecisionBookItemDebits",
#     #     back_populates="decision_book_payment_masters",
#     #     foreign_keys=[build_decision_book_item_debits_id],
#     # )
#     # parts: Mapped["BuildParts"] = relationship(
#     #     "BuildParts",
#     #     back_populates="decision_book_payment_master",
#     #     foreign_keys=[build_parts_id],
#     # )
#     # decision_book_payment_detail: Mapped[List["BuildDecisionBookPaymentsDetail"]] = (
#     #     relationship(
#     #         "BuildDecisionBookPaymentsDetail",
#     #         back_populates="decision_book_master",
#     #         foreign_keys="BuildDecisionBookPaymentsDetail.build_decision_book_payments_master_id",
#     #     )
#     # )
#
#     __table_args__ = (
#         Index(
#             "_build_decision_book_payments_master_ndx_00",
#             build_decision_book_item_debits_id,
#             build_parts_id,
#             dues_types_id,
#             unique=True,
#         ),
#         {
#             "comment": "Master Payment Items related to decision taken at building meetings"
#         },
#     )
#
#     # @classmethod
#     # def pay_dues_of_build_part(
#     #     cls,
#     #     budget_records_id,
#     #     build_decision_book_id,
#     #     build_parts_id,
#     #     start_date,
#     #     paid_value,
#     #     is_all=False,
#     #     is_limited=False,
#     # ):
#     #
#     #     book_payment_master = cls.find_one(
#     #         build_decision_book_id=build_decision_book_id,
#     #         build_parts_id=build_parts_id,
#     #         dues_types=BuildDuesTypes.D.name,
#     #     )
#     #     paid_amount = 0
#     #     if book_payment_master:
#     #         month_start_date = (
#     #             find_first_day_of_month(start_date)
#     #             if not is_all
#     #             else datetime(1900, 1, 1)
#     #         )
#     #         last_date = (
#     #             find_last_day_of_month(start_date) if not is_limited else start_date
#     #         )
#     #         payment_dues, count = BuildDecisionBookPaymentsDetail.filter(
#     #             and_(
#     #                 BuildDecisionBookPaymentsDetail.build_decision_book_payments_master_id
#     #                 == book_payment_master.id,
#     #                 BuildDecisionBookPaymentsDetail.process_date >= month_start_date,
#     #                 BuildDecisionBookPaymentsDetail.process_date <= last_date,
#     #             )
#     #         )
#     #         period_amount = {}
#     #         for payment_due in payment_dues:
#     #             if payment_due.period_time not in period_amount:
#     #                 period_amount[payment_due.period_time] = 0
#     #             period_amount[payment_due.period_time] += float(
#     #                 payment_due.payment_amount
#     #             )
#     #             paid_amount += payment_due.payment_amount
#     #         print(
#     #             "period_amount",
#     #             period_amount,
#     #             "paid_amount",
#     #             paid_amount,
#     #             "paid_value",
#     #             paid_value,
#     #         )
#     #         if paid_amount > 0:
#     #             return float(paid_value)
#     #         period_amounts = sorted(
#     #             period_amount.items(), key=lambda x: x[0], reverse=False
#     #         )
#     #         for period_amount in period_amounts:
#     #             if period_amount[1] >= 0:
#     #                 continue
#     #             if not paid_value > 0:
#     #                 break
#     #             if budget_record := CompanyBudgetRecords.find_one(id=budget_records_id):
#     #                 debit_to_pay = abs(float(period_amount[1]))
#     #                 debit_to_pay = (
#     #                     paid_value if debit_to_pay > paid_value else debit_to_pay
#     #                 )
#     #                 budget_record.remainder_balance = float(debit_to_pay) + float(
#     #                     budget_record.remainder_balance
#     #                 )
#     #                 budget_record.save()
#     #                 BuildDecisionBookPaymentsDetail.find_or_create(
#     #                     build_decision_book_payments_master_id=book_payment_master.id,
#     #                     budget_records_id=budget_records_id,
#     #                     process_date=str(start_date),
#     #                     receive_debit=DebitTypes.R.name,
#     #                     period_time=str(period_amount[0]),
#     #                     process_date_y=str(period_amount[0]).split("-")[0],
#     #                     process_date_m=str(period_amount[0]).split("-")[1],
#     #                     payment_amount=abs(debit_to_pay),
#     #                 )
#     #                 paid_value = float(paid_value) - float(debit_to_pay)
#     #     return float(paid_value)
#     #

#
# class BuildDecisionBookItemDebits(CrudCollection):
#     """
#     Builds class based on declarative_base and BaseMixin via session
#     dues_values = due_key, due_value
#     """
#
#     __tablename__ = "build_decision_book_item_debits"
#     __exclude__fields__ = []
#     __enum_list__ = [("dues_types", "BuildDuesTypes", "D")]
#
#     dues_types_id: Mapped[int] = mapped_column(ForeignKey("api_enum_dropdown.id"), nullable=True)
#     dues_types_uu_id = mapped_column(String, nullable=True, comment="Dues Type UUID")
#     # dues_values = mapped_column(
#     #     MutableDict.as_mutable(JSONB()),
#     #     nullable=False,
#     #     comment="Due Part Key Description of inner parts",
#     # )
#     flat_type = mapped_column(
#         String, nullable=True, comment="Flat Type of Building Part"
#     )
#     flat_payment = mapped_column(
#         Numeric(20, 2), nullable=True, comment="Flat Payment Amount"
#     )
#     decision_taken: Mapped[bool] = mapped_column(Boolean, server_default="0")
#
#     build_decision_book_item_id = mapped_column(
#         ForeignKey("build_decision_book_items.id"), nullable=False
#     )
#     build_decision_book_item_uu_id = mapped_column(
#         String, nullable=True, comment="Decision Book Item UUID"
#     )
#
#     @classmethod
#     def select_action(cls, duty_id, token=None):
#         from database_sql_models import Companies
#
#         related_companies = Companies.select_action(duty_id=duty_id)
#         related_companies_ids = list(
#             related_.id for related_ in related_companies.all()
#         )
#         related_building = Build.query.filter(
#             Build.company_id.in_(related_companies_ids)
#         )
#         related_building_ids = list(related_.id for related_ in related_building.all())
#         related_decision_books = BuildDecisionBook.query.filter(
#             BuildDecisionBook.build_id.in_(related_building_ids)
#         )
#         related_decision_books_ids = list(
#             related_.id for related_ in related_decision_books.all()
#         )
#         related_decision_books_items = BuildDecisionBookItems.query.filter(
#             BuildDecisionBookItems.build_decision_book_id.in_(
#                 related_decision_books_ids
#             )
#         )
#         related_decision_books_items_ids = list(
#             related_.id for related_ in related_decision_books_items.all()
#         )
#         return cls.query.filter(
#             cls.build_decision_book_item_id.in_(related_decision_books_items_ids)
#         )
#
#     @classmethod
#     def create_action(cls, data: InsertBuildDecisionBookItemDebits, token):
#         from database_sql_models import ApiEnumDropdown
#         from application.shared_functions import find_last_day_of_month
#
#         data_dict = data.dump()
#         BuildDecisionBookItems.pre_query = BuildDecisionBookItems.select_action(
#             duty_id=token.duty_list["duty_id"]
#         )
#         cls.pre_query = cls.select_action(duty_id=token.duty_list["duty_id"])
#         if decision_book_item := BuildDecisionBookItems.find_one_or_abort(
#             uu_id=data.build_decision_book_item_uu_id
#         ):
#             data_dict["build_decision_book_item_id"] = decision_book_item.id
#             dues_values, payment_master_list = data_dict["dues_values"], []
#             data_dict["is_confirmed"] = True
#             del data_dict["build_decision_book_item_uu_id"]
#             item_debits = cls.find_or_create(**data_dict)
#             debit_dropdown = ApiEnumDropdown.find_one(
#                 enum_class="DebitTypes", value="Debit"
#             )
#             for dues_key, dues_value in dues_values.items():
#                 building_parts = decision_book_item.decision_books.buildings.parts
#                 decision_book = decision_book_item.decision_books
#                 for building_part in building_parts:
#                     detail_list = []
#                     if str(building_part.due_part_key) == str(dues_key):
#                         book_master = BuildDecisionBookPaymentsMaster.create(
#                             build_decision_book_item_debits_id=item_debits.id,
#                             build_parts_id=building_part.id,
#                             dues_types=debit_dropdown.uu_id,
#                             payment_plan_time_periods="M",
#                             default_payment_amount=dues_value,
#                             is_confirmed=True,
#                         )
#                         if book_master:
#                             start_date = decision_book.expiry_starts
#                             while start_date <= decision_book.expiry_ends:
#                                 start_date = find_last_day_of_month(start_date)
#                                 data_detail = BuildDecisionBookPaymentsDetail.find_or_create(
#                                     build_decision_book_payments_master_id=book_master.id,
#                                     budget_records_id=None,
#                                     process_date=start_date,
#                                     receive_debit=debit_dropdown.uu_id,
#                                     period_time=start_date.strftime("%Y-%m"),
#                                     process_date_y=start_date.year,
#                                     process_date_m=start_date.month,
#                                     accounting_id=None,
#                                     payment_amount=float(dues_value) * -1,
#                                     is_confirmed=True,
#                                 )
#                                 start_date = start_date + timedelta(days=2)
#                                 detail_list.append(data_detail.get_dict())
#                         payment_master_list.append(
#                             {**book_master.get_dict(), "detail_list": detail_list}
#                         )
#             return_dict = {
#                 **item_debits.get_dict(),
#                 "debit_lists": payment_master_list,
#             }
#             return return_dict
#
#     __table_args__ = (
#         {
#             "comment": "Debits of Decision Book Items that are related to decision taken at building meetings"
#         },
#     )


#
# class BuildDecisionBookBudget(CrudCollection):
#     """
#     Builds class based on declarative_base and BaseMixin via session
#     """
#
#     __tablename__ = "build_decision_book_budget"
#
#     item_order = mapped_column(SmallInteger, nullable=False, comment="Order Number")
#     budget_type = mapped_column(String, nullable=False, comment="Budget Type")
#     plan_value: Mapped[float] = mapped_column(Numeric(10, 2), nullable=False, comment="Plan Value")
#
#     line_comment = mapped_column(String(32), server_default="")
#     process_date_y: Mapped[int] = mapped_column(SmallInteger)
#     process_date_m: Mapped[int] = mapped_column(SmallInteger)
#     process_date_w: Mapped[int] = mapped_column(SmallInteger)
#     period_time = mapped_column(String(12), server_default="")
#
#     build_decision_book_id: Mapped[int] = mapped_column(ForeignKey("build_decision_book.id"))
#     accounting_id = mapped_column(ForeignKey("account_detail.id"))
#
#     __table_args__ = (
#         Index("_build_decision_book_budget_ndx_01", accounting_id),
#         {"comment": "Budget Items related to decision taken at building meetings"},
#     )
#
#
# class BuildDecisionBookBudgetItem(CrudCollection):
#     """
#     Builds class based on declarative_base and BaseMixin via session
#     """
#
#     __tablename__ = "build_decision_book_budget_item"
#     __exclude__fields__ = []
#
#     paid_date = mapped_column(TIMESTAMP, nullable=False, comment="Payment Due Date")
#     period_time = mapped_column(String(12), server_default="")
#     paid_value: Mapped[float] = mapped_column(Numeric(10, 2), server_default="0")
#
#     build_decision_book_budget_id = mapped_column(
#         ForeignKey("build_decision_book_budget.id"), nullable=False
#     )
#
#     __table_args__ = (
#         Index(
#             "_build_decision_book_budget_item_ndx_01",
#             build_decision_book_budget_id,
#             paid_date,
#         ),
#     )
#


# buildings: Mapped["Build"] = relationship(
#     "Build", back_populates="decision_books", foreign_keys=[build_id]
# )
# companies: Mapped[List["Company"]] = relationship(
#     "Company", back_populates="decision_books", foreign_keys=[resp_company_id]
# )
# budget_records: Mapped[List["CompanyBudgetRecords"]] = relationship(
#     "CompanyBudgetRecords",
#     back_populates="decision_books",
#     foreign_keys="CompanyBudgetRecords.build_decision_book_id",
# )
# decision_book_items: Mapped[List["BuildDecisionBookItems"]] = relationship(
#     "BuildDecisionBookItems",
#     back_populates="decision_books",
#     foreign_keys="BuildDecisionBookItems.build_decision_book_id",
# )
#
# decision_book_management: Mapped["BuildDecisionBookManagement"] = relationship(
#     "BuildDecisionBookManagement",
#     back_populates="decision_book",
#     foreign_keys="BuildDecisionBookManagement.build_decision_book_id",
# )
#
# decision_book_people: Mapped[List["BuildDecisionBookPerson"]] = relationship(
#     "BuildDecisionBookPerson",
#     back_populates="decision_books",
#     foreign_keys="BuildDecisionBookPerson.build_decision_book_id",
# )
#
# # decision_book_projects: Mapped[List["DecisionBookProjects"]] = relationship(
# #     "DecisionBookProjects",
# #     back_populates="decision_books",
# #     foreign_keys="DecisionBookProjects.build_decision_book_id",
# # )
# # decision_book_project_people: Mapped[List["BuildDecisionBookProjectPerson"]] = (
# #     relationship(
# #         "BuildDecisionBookProjectPerson",
# #         back_populates="decision_books",
# #         foreign_keys="BuildDecisionBookProjectPerson.build_decision_book_id",
# #     )
# # )
# decision_book_legal_people: Mapped["BuildDecisionBookProjectsLegal"] = relationship(
#     "BuildDecisionBookProjectsLegal",
#     back_populates="decision_books",
#     foreign_keys="BuildDecisionBookProjectsLegal.build_decision_book_id",
# )
#
# decision_book_budget: Mapped["BuildDecisionBookBudget"] = relationship(
#     "BuildDecisionBookBudget",
#     back_populates="decision_book",
#     foreign_keys="BuildDecisionBookBudget.build_decision_book_id",
# )

# decision_book_items: Mapped[List["BuildDecisionBookItems"]] = relationship(
#     "BuildDecisionBookItems",
#     back_populates="decision_book_item_debits",
#     foreign_keys=[build_decision_book_item_id],
# )
# decision_book_payment_masters: Mapped[List["BuildDecisionBookPaymentsMaster"]] = relationship(
#     "BuildDecisionBookPaymentsMaster",
#     back_populates="decision_books_item_debits",
#     foreign_keys="BuildDecisionBookPaymentsMaster.build_decision_book_item_debits_id",
# )
#
# decision_books: Mapped["BuildDecisionBook"] = relationship(
#     "BuildDecisionBook",
#     back_populates="decision_book_items",
#     foreign_keys=[build_decision_book_id],
# )
# decision_book_item_debits: Mapped[List["BuildDecisionBookItemDebits"]] = (
#     relationship(
#         "BuildDecisionBookItemDebits",
#         back_populates="decision_book_items",
#         foreign_keys="BuildDecisionBookItemDebits.build_decision_book_item_id",
#     )
# )
# decision_book_projects: Mapped["DecisionBookProjects"] = relationship(
#     "DecisionBookProjects",
#     back_populates="decision_book_items",
#     foreign_keys="DecisionBookProjects.build_decision_book_item_id",
# )
# decision_book_legal: Mapped["BuildDecisionBookLegal"] = relationship(
#     "BuildDecisionBookLegal",
#     back_populates="decision_books_items",
#     foreign_keys="BuildDecisionBookLegal.build_db_item_id",
# )
#
# build_decision_book_item_unapproved: Mapped[
#     List["BuildDecisionBookItemsUnapproved"]
# ] = relationship(
#     "BuildDecisionBookItemsUnapproved",
#     back_populates="decision_book_items",
#     foreign_keys="BuildDecisionBookItemsUnapproved.build_decision_book_item",
# )

# decision_books_items: Mapped["BuildDecisionBookItems"] = relationship(
#     "BuildDecisionBookItems",
#     back_populates="decision_book_legal",
#     foreign_keys=[build_db_item_id],
# )
# attorney_companies: Mapped["Companies"] = relationship(
#     "Company",
#     back_populates="decision_book_legal",
#     foreign_keys=[resp_attorney_company],
# )
# attorney_persons: Mapped["People"] = relationship(
#     "People",
#     back_populates="attorney_decision_book_legal",
#     foreign_keys=[resp_attorney_id],
# )
# lawyer_persons: Mapped["People"] = relationship(
#     "People",
#     back_populates="lawyer_decision_book_legal",
#     foreign_keys=[mediator_lawyer_person_id],
# )

# decision_books: Mapped["BuildDecisionBook"] = relationship(
#     "BuildDecisionBook",
#     back_populates="decision_book_people",
#     foreign_keys=[build_decision_book_id],
# )
# people: Mapped["People"] = relationship(
#     "People", back_populates="decision_book_people", foreign_keys=[person_id]
# )

# decision_book_budget: Mapped["BuildDecisionBookBudget"] = relationship(
#     "BuildDecisionBookBudget",
#     back_populates="decision_book_budget_item",
#     foreign_keys=[build_decision_book_budget_id],
# )

# accounting: Mapped["AccountDetail"] = relationship(
#     "AccountDetail",
#     back_populates="decision_book_budget",
#     foreign_keys=[accounting_id],
# )
# decision_book: Mapped["BuildDecisionBook"] = relationship(
#     "BuildDecisionBook",
#     back_populates="decision_book_budget",
#     foreign_keys=[build_decision_book_id],
# )
# decision_book_budget_item: Mapped["BuildDecisionBookBudgetItem"] = relationship(
#     "BuildDecisionBookBudgetItem",
#     back_populates="decision_book_budget",
#     foreign_keys="BuildDecisionBookBudgetItem.build_decision_book_budget_id",
# )

# decision_book_items: Mapped["BuildDecisionBookItems"] = relationship(
#     "BuildDecisionBookItems",
#     back_populates="build_decision_book_item_unapproved",
#     foreign_keys=[build_decision_book_item],
# )
#
# peoples: Mapped["People"] = relationship(
#     "People",
#     back_populates="build_decision_book_item_unapproved",
#     foreign_keys=[person_id],
# )
#
# class BuildDecisionBookInvitationsPerson(CrudCollection):
#     """
#     Builds class based on declarative_base and BaseMixin via session
#     """
#
#     __tablename__ = "build_decision_book_invitations_person"
#     __exclude__fields__ = []
#
#     invite_id = mapped_column(ForeignKey("build_decision_book_invitations.id"), nullable=False)
#     invite_uu_id = mapped_column(String, nullable=True, comment="Invite UUID")
#     person_id = mapped_column(ForeignKey("people.id"), nullable=False)
#     person_uu_id = mapped_column(String, nullable=False, comment="Person UUID")
#
#     send_date = mapped_column(TIMESTAMP, nullable=False, comment="Confirmation Date")
#     is_confirmed: Mapped[bool] = mapped_column(Boolean, server_default="0", comment="Message is Confirmed")
#     confirmed_date = mapped_column(TIMESTAMP, nullable=True, comment="Confirmation Date")
#     token = mapped_column(String, server_default="", comment="Invitation Token")
#
#     __table_args__ = (
#         Index(
#             "decision_book_invitations_person_ndx_01",
#             invite_id,
#             person_id,
#             unique=True,
#         ),
#         {"comment": "People that are invited to building meetings."},
#     )
