from databases.sql_models.core_mixin import CrudCollection
from databases.language_models.event.event import (
    EventsLanguageModel,
    ModulesLanguageModel,
    ServicesLanguageModel,
    Service2EventsLanguageModel,
    Event2OccupantExtraLanguageModel,
    Event2EmployeeExtraLanguageModel,
    Event2EmployeeLanguageModel,
    Event2OccupantLanguageModel,
    ModulePriceLanguageModel,
)

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


class Events(CrudCollection):
    """
    Events class based on declarative_base and BaseMixin via session
    If Events2Occupants and Events2Employees are not found for user request, response 401 Unauthorized
    """

    __tablename__ = "events"
    __exclude__fields__ = []
    __language_model__ = EventsLanguageModel

    event_type: Mapped[str] = mapped_column(
        String, nullable=False, comment="Event Type"
    )
    function_code: Mapped[str] = mapped_column(
        String, nullable=False, comment="function code"
    )
    function_class: Mapped[str] = mapped_column(
        String, nullable=False, comment="class name"
    )

    # name: Mapped[str] = mapped_column(String, nullable=True)  # form or page title
    description: Mapped[str] = mapped_column(
        String, server_default=""
    )  # form or page description
    property_description: Mapped[str] = mapped_column(String, server_default="")

    marketing_layer = mapped_column(SmallInteger, server_default="3")
    cost: Mapped[float] = mapped_column(Numeric(20, 2), server_default="0.00")
    unit_price: Mapped[float] = mapped_column(Numeric(20, 2), server_default="0.00")

    endpoint_id: Mapped[int] = mapped_column(
        ForeignKey("endpoint_restriction.id"), nullable=True
    )
    endpoint_uu_id: Mapped[str] = mapped_column(
        String, nullable=True, comment="Endpoint UUID"
    )

    __table_args__ = ({"comment": "Events Information"},)


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

    __tablename__ = "modules"
    __exclude__fields__ = []
    __language_model__ = ModulesLanguageModel

    module_name: Mapped[str] = mapped_column(
        String, nullable=False, comment="Module Name"
    )
    module_description: Mapped[str] = mapped_column(String, server_default="")
    module_code: Mapped[str] = mapped_column(
        String, nullable=False, comment="Module Code"
    )
    module_layer = mapped_column(Integer, nullable=False, comment="Module Layer")
    is_default_module = mapped_column(Boolean, server_default="0")

    def retrieve_services(self):
        services = Services.filter_all(Services.module_id == self.id).data
        if not services:
            self.raise_http_exception(
                status_code="HTTP_404_NOT_FOUND",
                error_case="RECORD_NOT_FOUND",
                message=f"No services found for this module : {str(self.uu_id)}",
                data={
                    "module_uu_id": str(self.uu_id),
                },
            )
        return services

    __table_args__ = ({"comment": "Modules Information"},)


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

    __tablename__ = "services"
    __exclude__fields__ = []
    __language_model__ = ServicesLanguageModel

    module_id: Mapped[int] = mapped_column(ForeignKey("modules.id"), nullable=False)
    module_uu_id: Mapped[str] = mapped_column(
        String, nullable=False, comment="Module UUID"
    )
    service_name: Mapped[str] = mapped_column(
        String, nullable=False, comment="Service Name"
    )
    service_description: Mapped[str] = mapped_column(String, server_default="")
    service_code: Mapped[str] = mapped_column(
        String, nullable=True, comment="Service Code"
    )
    related_responsibility: Mapped[str] = mapped_column(String, server_default="")

    @classmethod
    def retrieve_service_via_occupant_code(cls, occupant_code):
        from databases import OccupantTypes

        occupant_type = OccupantTypes.filter_by_one(
            system=True,
            occupant_code=occupant_code,
        ).data
        if not occupant_type:
            cls.raise_http_exception(
                status_code="HTTP_404_NOT_FOUND",
                error_case="RECORD_NOT_FOUND",
                message=f"No occupant type found for this code : {occupant_code}",
                data={
                    "occupant_code": occupant_code,
                },
            )
        return cls.filter_one(
            cls.related_responsibility == occupant_type.occupant_code
        ).data

    __table_args__ = ({"comment": "Services Information"},)


class Service2Events(CrudCollection):
    """
    Service2Actions class based on declarative_base and BaseMixin via session
    """

    __tablename__ = "services2events"
    __exclude__fields__ = []
    __language_model__ = Service2EventsLanguageModel

    service_id: Mapped[int] = mapped_column(ForeignKey("services.id"), nullable=False)
    service_uu_id = mapped_column(String, nullable=False, comment="Service UUID")
    event_id: Mapped[int] = mapped_column(ForeignKey("events.id"), nullable=False)
    event_uu_id = mapped_column(String, nullable=False, comment="Event UUID")

    __table_args__ = ({"comment": "Service2Events Information"},)


class Event2OccupantExtra(CrudCollection):

    __tablename__ = "event2occupant_extra"
    __exclude__fields__ = []
    __language_model__ = Event2OccupantExtraLanguageModel

    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=False, comment="Build Living Space UUID"
    )
    event_id: Mapped[int] = mapped_column(ForeignKey("events.id"), nullable=False)
    event_uu_id: Mapped[str] = mapped_column(
        String, nullable=False, comment="Event UUID"
    )

    __table_args__ = (
        Index(
            "event2occupant_extra_bind_event_to_occupant",
            build_living_space_id,
            event_id,
            unique=True,
        ),
        {"comment": "Occupant2Event Information"},
    )


class Event2EmployeeExtra(CrudCollection):
    """
    Employee2Event class based on declarative_base and BaseMixin via session
    """

    __tablename__ = "event2employee_extra"
    __exclude__fields__ = []
    __language_model__ = Event2EmployeeExtraLanguageModel

    employee_id: Mapped[int] = mapped_column(ForeignKey("employees.id"), nullable=False)
    employee_uu_id: Mapped[str] = mapped_column(
        String, nullable=False, comment="Employee UUID"
    )

    event_id: Mapped[int] = mapped_column(ForeignKey("events.id"), nullable=False)
    event_uu_id: Mapped[str] = mapped_column(
        String, nullable=False, comment="Event UUID"
    )

    __table_args__ = (
        Index(
            "event2employee_extra_employee_to_event",
            employee_id,
            event_id,
            unique=True,
        ),
        {"comment": "Employee to Event Information"},
    )


class Event2Employee(CrudCollection):
    """
    Employee2Event class based on declarative_base and BaseMixin via session
    """

    __tablename__ = "event2employee"
    __exclude__fields__ = []
    __language_model__ = Event2EmployeeLanguageModel

    employee_id: Mapped[int] = mapped_column(ForeignKey("employees.id"), nullable=False)
    employee_uu_id: Mapped[str] = mapped_column(
        String, nullable=False, comment="Employee UUID"
    )
    event_service_id: Mapped[int] = mapped_column(
        ForeignKey("services.id"), nullable=False
    )
    event_service_uu_id: Mapped[str] = mapped_column(
        String, nullable=False, comment="Event Cluster UUID"
    )

    __table_args__ = (
        Index(
            "event2employee_employee_to_event",
            employee_id,
            event_service_id,
            unique=True,
        ),
        {"comment": "Employee to Event Information"},
    )

    @classmethod
    def get_event_id_by_employee_id(cls, employee_id) -> list:
        occupant_events = cls.filter_all(
            cls.employee_id == employee_id,
        ).data
        active_events = Service2Events.filter_all(
            Service2Events.service_id.in_(
                [event.event_service_id for event in occupant_events]
            ),
            system=True,
        ).data
        active_events_id = [event.event_id for event in active_events]
        if extra_events := Event2EmployeeExtra.filter_all(
            Event2EmployeeExtra.employee_id == employee_id
        ).data:
            active_events_id.extend([event.event_id for event in extra_events])
        return active_events_id


class Event2Occupant(CrudCollection):
    """
    Occupant2Event class based on declarative_base and BaseMixin via session
    """

    __tablename__ = "event2occupant"
    __exclude__fields__ = []
    __language_model__ = Event2OccupantLanguageModel

    build_living_space_id: Mapped[str] = mapped_column(
        ForeignKey("build_living_space.id"), nullable=False
    )
    build_living_space_uu_id: Mapped[str] = mapped_column(
        String, nullable=False, comment="Build Living Space UUID"
    )
    event_service_id: Mapped[int] = mapped_column(
        ForeignKey("services.id"), nullable=False
    )
    event_service_uu_id: Mapped[str] = mapped_column(
        String, nullable=False, comment="Event Cluster UUID"
    )
    # event_id: Mapped[int] = mapped_column(ForeignKey("events.id"), nullable=False)
    # event_uu_id = mapped_column(String, nullable=False, comment="Event UUID")

    __table_args__ = (
        Index(
            "event2occupant_bind_event_to_occupant",
            build_living_space_id,
            event_service_id,
            unique=True,
        ),
        {"comment": "Occupant2Event Information"},
    )

    @classmethod
    def get_event_id_by_build_living_space_id(cls, build_living_space_id) -> list:
        occupant_events = cls.filter_all(
            cls.build_living_space_id == build_living_space_id,
        ).data
        active_events = Service2Events.filter_all(
            Service2Events.service_id.in_(
                [event.event_service_id for event in occupant_events]
            ),
            system=True,
        ).data
        active_events_id = [event.event_id for event in active_events]
        if extra_events := Event2OccupantExtra.filter_all(
            Event2OccupantExtra.build_living_space_id == build_living_space_id
        ).data:
            active_events_id.extend([event.event_id for event in extra_events])
        return active_events_id


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

    __tablename__ = "module_price"
    __exclude__fields__ = []
    __language_model__ = ModulePriceLanguageModel

    campaign_code: Mapped[str] = mapped_column(
        String, nullable=False, comment="Campaign Code"
    )
    module_id: Mapped[int] = mapped_column(ForeignKey("modules.id"), nullable=False)
    module_uu_id: Mapped[str] = mapped_column(
        String, nullable=False, comment="Module UUID"
    )
    service_id: Mapped[int] = mapped_column(ForeignKey("services.id"), nullable=False)
    service_uu_id: Mapped[str] = mapped_column(
        String, nullable=False, comment="Service UUID"
    )
    event_id: Mapped[int] = mapped_column(ForeignKey("events.id"), nullable=False)
    event_uu_id: Mapped[str] = mapped_column(
        String, nullable=False, comment="Event UUID"
    )
    is_counted_percentage: Mapped[float] = mapped_column(
        Numeric(6, 2), server_default="0.00"
    )  # %22
    discounted_price: Mapped[float] = mapped_column(
        Numeric(20, 2), server_default="0.00"
    )  # Normal: 78.00 TL
    calculated_price: Mapped[float] = mapped_column(
        Numeric(20, 2), server_default="0.00"
    )  # sana düz 75.00 TL yapar

    __table_args__ = ({"comment": "ModulePrice Information"},)
