from typing import Any, Self

from sqlalchemy import (
    ColumnElement as ColumnElement,
    Select as Select,
    UnaryExpression as UnaryExpression,
)
from sqlalchemy.orm import Session as Session

from ..errors import ERROR_ENTITY_DOES_NOT_EXIST as ERROR_ENTITY_DOES_NOT_EXIST
from ..types.executor import Executor as Executor
from ..utils import get_pk as get_pk

class BaseMixin:
    """Base mixin for common functionality."""

    @classmethod
    def build(cls, session: Session, **kwargs):
        """Construct a new object without persisting it."""
    @classmethod
    def create(cls, session: Session, **kwargs):
        """Persist a new object."""
    @classmethod
    def default_filter(cls, stmt: Select[Any] | None = None) -> Select[Any]:
        """Get select statement with default filter applied.

        Models should override `_get_default_filter()` to define their filtering logic.
        If no filter is defined, the statement is returned unchanged.

        Args:
            stmt: Optional base select statement. If not provided, uses select(cls)

        Returns:
            Select statement with default filter applied (or unchanged if no filter defined)

        Example:
        ```python
        # Create new statement with default filter
        stmt = AbacusEvent.default_filter()

        # Apply default filter to existing statement
        stmt = select(AbacusEvent).join(SomeTable)
        stmt = AbacusEvent.default_filter(stmt)
        ```
        """
    @classmethod
    def default_order(cls, stmt: Select[Any] | None = None) -> Select[Any]:
        """Get select statement with default ordering applied.

        Models should override `_get_default_order()` to define their ordering logic.
        If no ordering is defined, the statement is returned unchanged.

        Args:
            stmt: Optional base select statement. If not provided, uses select(cls)

        Returns:
            Select statement with default ordering applied (or unchanged if no ordering defined)

        Example:
        ```python
        # Create new statement with default ordering
        stmt = AbacusEvent.default_order()

        # Apply default ordering to existing statement
        stmt = select(AbacusEvent).where(AbacusEvent.id > 100)
        stmt = AbacusEvent.default_order(stmt)

        # Combine with default_filter
        stmt = AbacusEvent.default_filter()
        stmt = AbacusEvent.default_order(stmt)
        ```
        """
    @classmethod
    def get_by_id(cls, executor: Executor, obj_id):
        """Get object from DB by ID property."""
    @classmethod
    def get_by_id_or_error(cls, executor: Executor, obj_id):
        """Find object by ID. Abort request if not found."""
    @classmethod
    def get_class_name(cls) -> str:
        """Return name of the subclass."""
    @classmethod
    def count(cls, executor: Executor, *where_clauses: ColumnElement[bool]) -> int:
        """Count rows, optionally filtered.

        Args:
            executor: SQLAlchemy Session or Connection
            *where_clauses: Optional filter conditions

        Returns:
            Number of matching rows
        """
    def update_attributes(self, session: Session, **attrs) -> Self:
        """Update instance attributes.

        UpdateMixin handles last_modified/last_modified_by automatically
        via before_update event listener when the session flushes.

        Args:
            session: SQLAlchemy session (for API consistency with create/build)
            **attrs: Attribute key-value pairs to update

        Raises:
            AttributeError: If an attribute does not exist on the model
        """
