"""邀请指纹归因表(剪贴板归因兜底)。

数据流(对应 [[invite-three-tasks]] 任务 3):
  1. B 浏览器打开落地页 dl.html?ref=邀请码 → JS POST /api/v1/invite/landing-track
  2. 后端从 HTTP 头拿 IP/UA,解析 UA 得 device_model,跟 JS 上报的 screen 一起入库
  3. B 装包首启 → 登录后,若剪贴板没拿到邀请码(被覆盖),客户端再算一次 screen+Build.MODEL
     上报 → 后端用 (ip, screen, device_model) 反查本表 7 天内最近匹配 → 拿出 inviter_user_id
     → 走原 bind 路径(channel=fingerprint)

不要索引(IP, created_at) 单独,组合索引 (ip, screen, device_model, created_at desc) 反查更省。
"""
from __future__ import annotations

from datetime import datetime

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

from app.db.base import Base


class InviteFingerprint(Base):
    __tablename__ = "invite_fingerprint"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    inviter_user_id: Mapped[int] = mapped_column(
        Integer, ForeignKey("user.id"), index=True, nullable=False
    )
    # 落地页访问者 IP(服务端从 HTTP 头拿,X-Forwarded-For 由部署侧 nginx 透传)
    ip: Mapped[str] = mapped_column(String(64), nullable=False)
    # 客户端 Build.MODEL / 浏览器 UA 解析出来的型号(如 "PJF110"、"23046PNC9C")
    device_model: Mapped[str] = mapped_column(String(64), nullable=False, default="")
    # 屏幕分辨率 "1080x2400"(浏览器 screen.width × height,客户端 DisplayMetrics)
    screen: Mapped[str] = mapped_column(String(32), nullable=False, default="")
    # 完整 UA 字符串(留 debug / 排查"匹配不上"用,不直接参与匹配)
    user_agent: Mapped[str] = mapped_column(Text, nullable=False, default="")

    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), index=True, nullable=False
    )

    def __repr__(self) -> str:  # pragma: no cover
        return (
            f"<InviteFingerprint inviter={self.inviter_user_id} "
            f"ip={self.ip} model={self.device_model} screen={self.screen}>"
        )
