from __future__ import annotations

from datetime import datetime, timezone
from typing import Optional

from sqlalchemy import DateTime, ForeignKey, Integer, String
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql import func

from src.apps.base.models.base import Base


class AdminInvite(Base):
    __tablename__ = "admin_invites"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    email: Mapped[str] = mapped_column(String(255), nullable=False, index=True)
    admin_role_id: Mapped[int] = mapped_column(
        Integer, ForeignKey("admin_roles.id"), nullable=False
    )
    invited_user_id: Mapped[int] = mapped_column(
        Integer, ForeignKey("users.id", ondelete="CASCADE"),
        nullable=False, index=True,
    )
    invited_by_id: Mapped[int] = mapped_column(
        Integer, ForeignKey("users.id"), nullable=False
    )
    token_hash: Mapped[str] = mapped_column(
        String(64), nullable=False, unique=True, index=True
    )
    expires_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
    accepted_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime(timezone=True), nullable=True
    )
    cancelled_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime(timezone=True), nullable=True
    )
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now()
    )

    admin_role: Mapped["AdminRole"] = relationship(  # type: ignore[name-defined]
        "AdminRole", lazy="joined", uselist=False
    )
    invited_user: Mapped["User"] = relationship(  # type: ignore[name-defined]
        "User", foreign_keys=[invited_user_id], uselist=False
    )
    inviter: Mapped["User"] = relationship(  # type: ignore[name-defined]
        "User", foreign_keys=[invited_by_id], uselist=False
    )

    @property
    def is_expired(self) -> bool:
        return datetime.now(timezone.utc) > self.expires_at

    @property
    def is_pending(self) -> bool:
        return (
            self.accepted_at is None
            and self.cancelled_at is None
            and not self.is_expired
        )
