"""
使用者相關資料表 Model。

階段 1 只先建立兩張表:
  - users         ─ 帳號主表
  - user_skills   ─ 技能標籤(供階段 3 庫柏推薦負責人使用)

設計原則:
  1. 主鍵用 UUID v4(分散式友善、不會洩漏總筆數)
  2. 所有表都有 created_at, updated_at, deleted_at(軟刪除)
  3. email 全域唯一
  4. 角色只有 owner / member 兩種(微型團隊不需要複雜權限)
"""

from datetime import datetime
from uuid import UUID, uuid4

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

from app.database import Base


class TimestampMixin:
    """共用時間戳記欄位的 mixin。

    每張表都會有:
      - created_at: 建立時間(自動填)
      - updated_at: 最後更新時間(每次 UPDATE 自動更新)
      - deleted_at: 軟刪除時間(NULL = 未刪除,有值 = 已軟刪)

    軟刪除設計理由:庫柏需要保留「歷史脈絡」,真刪會切斷關聯。
    所有查詢預設要過濾 deleted_at IS NULL。
    """

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


class User(Base, TimestampMixin):
    """使用者帳號。

    role 設計:
      - owner  : 公司負責人 / 管理員,可以邀請成員、修改公司設定
      - member : 一般成員,可以使用所有協作功能

    第一個註冊成功的帳號自動成為 owner(由 seed 腳本建立),
    之後新加入的成員都是 member,要由 owner 手動升級。
    """

    __tablename__ = "users"

    # 主鍵 ─ UUID v4
    # 用 sa.Uuid 而非 postgresql.UUID:
    # PostgreSQL 自動用原生 UUID 型別,SQLite(測試環境)會 fallback 成 CHAR(32),
    # 程式碼一份、兩種環境都跑得起來。
    id: Mapped[UUID] = mapped_column(
        Uuid(as_uuid=True),
        primary_key=True,
        default=uuid4,
    )

    # 登入用 email(全域唯一,大小寫不敏感由應用層處理:存進去前 .lower())
    email: Mapped[str] = mapped_column(String(255), unique=True, nullable=False, index=True)

    # bcrypt 雜湊後的密碼(永遠不會明文存)
    password_hash: Mapped[str] = mapped_column(String(255), nullable=False)

    # 顯示名稱(對話方塊、任務指派看到的名字)
    display_name: Mapped[str] = mapped_column(String(100), nullable=False)

    # 頭像 URL(可選,初期可用文字頭像取代)
    avatar_url: Mapped[str | None] = mapped_column(String(500), nullable=True)

    # 角色:owner / member
    role: Mapped[str] = mapped_column(String(20), nullable=False, default="member")

    # 是否啟用(被 owner 停用的帳號 is_active=False,無法登入)
    is_active: Mapped[bool] = mapped_column(default=True, nullable=False)

    # 階段 6:LINE 帳號綁定。
    # 一個 LINE userId 對應一個 Cooper user(unique nullable)。
    # 沒綁定的 LINE 使用者會在第一次發訊息時建立「影子帳號」(password_hash="" 無法登入)。
    line_user_id: Mapped[str | None] = mapped_column(
        String(64), unique=True, nullable=True, index=True
    )

    # 反向關聯:這個使用者的所有技能標籤
    skills: Mapped[list["UserSkill"]] = relationship(
        back_populates="user",
        cascade="all, delete-orphan",
        lazy="selectin",
    )

    def __repr__(self) -> str:
        return f"<User {self.email} role={self.role}>"


class UserSkill(Base, TimestampMixin):
    """使用者技能標籤。

    用途:庫柏在「自動推薦任務負責人」時參考。
    例如某任務描述「要修 React 元件樣式」,庫柏會找到 skill_name='React' 且
    proficiency 高的成員推薦。

    proficiency:1(新手)~ 5(專家)
    """

    __tablename__ = "user_skills"

    id: Mapped[UUID] = mapped_column(Uuid(as_uuid=True), primary_key=True, default=uuid4)

    user_id: Mapped[UUID] = mapped_column(
        Uuid(as_uuid=True),
        ForeignKey("users.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
    )
    skill_name: Mapped[str] = mapped_column(String(100), nullable=False)
    proficiency: Mapped[int] = mapped_column(Integer, nullable=False, default=3)

    # 反向關聯回 User
    user: Mapped[User] = relationship(back_populates="skills")

    # 同一個 user 不能有重複的 skill_name
    __table_args__ = (
        Index("ux_user_skill_unique", "user_id", "skill_name", unique=True),
    )

    def __repr__(self) -> str:
        return f"<UserSkill user_id={self.user_id} skill={self.skill_name} lv={self.proficiency}>"
