from typing import TYPE_CHECKING, Optional
from collections.abc import Hashable

from sqlalchemy import ColumnElement, ForeignKey
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import relationship

from advanced_alchemy.base import BigIntAuditBase, BigIntBase
from advanced_alchemy.mixins import UniqueMixin

if TYPE_CHECKING:
    from .book import Book


class Author(BigIntAuditBase, UniqueMixin):
    __tablename__ = "authors"

    name: Mapped[str] = mapped_column(unique=True, index=True)
    description: Mapped[Optional[str]]

    @classmethod
    def unique_hash(cls, name: str) -> Hashable:
        """Generate a unique hash for deduplication."""
        return name

    @classmethod
    def unique_filter(cls, name: str) -> ColumnElement[bool]:
        """SQL filter for finding existing records."""
        return cls.name == name

    def __repr__(self) -> str:
        return f"Author({self.name!r})"


class BookAuthorLink(BigIntBase):
    __tablename__ = "book_author_links"

    book_id: Mapped[int] = mapped_column(
        ForeignKey("books.id", ondelete="cascade"), primary_key=True
    )
    author_id: Mapped[int] = mapped_column(ForeignKey("authors.id"), primary_key=True)

    position: Mapped[int]

    book: Mapped["Book"] = relationship(back_populates="author_links")
    author: Mapped[Author] = relationship()
