from __future__ import annotations

from datetime import datetime

from sqlalchemy import BigInteger, DateTime, ForeignKey, Index, Integer, String, Text, UniqueConstraint, func
from sqlalchemy.orm import Mapped, mapped_column

from app.models.base import Base


PRIMARY_KEY_TYPE = BigInteger().with_variant(Integer, "sqlite")


class SsoClient(Base):
    __tablename__ = "sys_sso_client"
    __table_args__ = (Index("ix_sys_sso_client_status", "status"),)

    id: Mapped[int] = mapped_column(PRIMARY_KEY_TYPE, primary_key=True, autoincrement=True)
    app_id: Mapped[str] = mapped_column(String(80), unique=True, index=True, nullable=False)
    name: Mapped[str] = mapped_column(String(100), nullable=False)
    client_secret: Mapped[str] = mapped_column(Text, nullable=False)
    redirect_uris: Mapped[str] = mapped_column(Text, default="[]", nullable=False)
    allow_auto_register: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    default_entitlement_plan_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
    status: Mapped[int] = mapped_column(Integer, default=1, nullable=False)
    created_by: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
    last_used_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
    updated_at: Mapped[datetime] = mapped_column(
        DateTime,
        server_default=func.now(),
        onupdate=func.now(),
        nullable=False,
    )


class UserExternalIdentity(Base):
    __tablename__ = "sys_user_external_identity"
    __table_args__ = (
        UniqueConstraint("client_id", "external_user_id", name="uq_sso_identity_client_external"),
        UniqueConstraint("client_id", "user_id", name="uq_sso_identity_client_user"),
        Index("ix_sso_identity_user", "user_id"),
    )

    id: Mapped[int] = mapped_column(PRIMARY_KEY_TYPE, primary_key=True, autoincrement=True)
    client_id: Mapped[int] = mapped_column(ForeignKey("sys_sso_client.id"), index=True, nullable=False)
    user_id: Mapped[int] = mapped_column(ForeignKey("sys_user.id"), nullable=False)
    external_user_id: Mapped[str] = mapped_column(String(120), nullable=False)
    phone_snapshot: Mapped[str | None] = mapped_column(String(20), nullable=True)
    display_name_snapshot: Mapped[str | None] = mapped_column(String(100), nullable=True)
    last_login_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
    updated_at: Mapped[datetime] = mapped_column(
        DateTime,
        server_default=func.now(),
        onupdate=func.now(),
        nullable=False,
    )


class SsoLoginAudit(Base):
    __tablename__ = "sys_sso_login_audit"
    __table_args__ = (
        Index("ix_sso_audit_client_created", "client_id", "created_at"),
        Index("ix_sso_audit_user_created", "user_id", "created_at"),
        Index("ix_sso_audit_status_created", "status", "created_at"),
    )

    id: Mapped[int] = mapped_column(PRIMARY_KEY_TYPE, primary_key=True, autoincrement=True)
    client_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
    user_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
    external_user_id: Mapped[str | None] = mapped_column(String(120), nullable=True)
    action: Mapped[str] = mapped_column(String(30), nullable=False)
    status: Mapped[str] = mapped_column(String(20), nullable=False)
    error_message: Mapped[str | None] = mapped_column(String(500), nullable=True)
    ip: Mapped[str | None] = mapped_column(String(50), nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), nullable=False)
