Загрузка данных


from datetime import datetime
from enum import Enum
from typing import List, Optional
from django.utils.translation import gettext_lazy as _
from pydantic import BaseModel, EmailStr, Field

# ==============================================================================
# ENUMS (Общие перечисления для валидации и выпадающих списков в OpenAPI)
# ==============================================================================

class GlobalRoleEnum(str, Enum):
    """Глобальные системные роли пользователей."""
    ADMIN = "admin"
    MANAGER = "manager"
    USER = "user"


class ProjectPermissionEnum(str, Enum):
    """Допустимые типы объектных прав django-guardian в системе Paprika."""
    VIEW = "view_project"
    EDIT = "edit_project"


# ==============================================================================
# 1. МОДУЛЬ: АУТЕНТИФИКАЦИЯ (AUTH)
# ==============================================================================

class LoginRequestSchema(BaseModel):
    """Схема запроса для аутентификации пользователя."""
    email: EmailStr = Field(
        description=_("Unique electronic address of the user registered in the system."),
        examples=["vfx_artist@paprika.studio"]
    )
    password: str = Field(
        min_length=8,
        max_length=128,
        description=_("User password. Must be at least 8 characters long."),
        examples=["p@ssw0rd_vfx_2026"]
    )


class LoginResponseSchema(BaseModel):
    """Схема успешного ответа при аутентификации (Access токен)."""
    access: str = Field(
        description=_("Short-lived JWT Access token. Passed in the 'Authorization: Bearer' header."),
        examples=["eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."]
    )


class RefreshRequestSchema(BaseModel):
    """Схема для эндпоинта обновления токена. Тело должно быть пустым (токен в куке)."""
    class Config:
        extra = "forbid"


class RefreshResponseSchema(BaseModel):
    """Схема успешного обновления сессии."""
    access: str = Field(
        description=_("New valid JWT Access token."),
        examples=["eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.new..."]
    )


class LogoutRequestSchema(BaseModel):
    """Схема запроса для выхода из системы (пустое тело)."""
    class Config:
        extra = "forbid"


class LogoutResponseSchema(BaseModel):
    """Схема ответа при успешном выходе из системы."""
    detail: str = Field(
        default="Successfully logged out.",
        description=_("Text confirmation of successful session termination."),
        examples=["Successfully logged out."]
    )


# ==============================================================================
# 2. МОДУЛЬ: ПРИГЛАШЕНИЯ (INVITATIONS)
# ==============================================================================

class InvitationProjectPermissionSchema(BaseModel):
    """Схема назначения прав на конкретный проект внутри инвайта."""
    project_id: int = Field(
        description=_("ID of the project to which access is granted."),
        examples=[12]
    )
    permission: ProjectPermissionEnum = Field(
        description=_("Permission level for the specified project."),
        examples=[ProjectPermissionEnum.VIEW]
    )


class InvitationCreateRequestSchema(BaseModel):
    """Схема запроса на создание инвайта администрацией."""
    email: EmailStr = Field(
        description=_("Email address where the invitation link will be sent."),
        examples=["vfx_artist@paprika.studio"]
    )
    role: GlobalRoleEnum = Field(
        default=GlobalRoleEnum.USER,
        description=_("Global system role assigned to the user after registration.")
    )
    project_permissions: Optional[List[InvitationProjectPermissionSchema]] = Field(
        default=None,
        description=_("List of initial project-level permissions that will be automatically assigned.")
    )


class InvitationResponseSchema(BaseModel):
    """Схема ответа с полной информацией о созданном инвайте."""
    id: str = Field(description=_("Unique string identifier of the invitation record."), examples=["inv_8f2b3c9d"])
    email: EmailStr = Field(description=_("Email address for which the invitation was generated."))
    role: GlobalRoleEnum = Field(description=_("Target global role for the invitee."))
    token: str = Field(description=_("Secure unique token included in the registration URL."), examples=["usr_tkn_abc123"])
    status: str = Field(description=_("Current status of the invitation."), examples=["pending"])
    invited_by: int = Field(description=_("ID of the administrator who issued the invitation."), examples=[1])
    created_at: datetime = Field(description=_("Timestamp when the invitation was created."))
    expires_at: datetime = Field(description=_("Timestamp after which the invitation link becomes invalid."))


class InvitationValidateResponseSchema(BaseModel):
    """Схема ответа для публичного эндпоинта валидации токена на фронтенде."""
    email: EmailStr = Field(description=_("Email address bound to this token."))
    role: GlobalRoleEnum = Field(description=_("Target role for the user."))
    status: str = Field(description=_("Status of the token."), examples=["pending"])
    expires_at: datetime = Field(description=_("Token expiration timestamp."))


class InvitationAcceptRequestSchema(BaseModel):
    """Схема запроса завершения регистрации от самого пользователя."""
    first_name: str = Field(max_length=150, description=_("User's given name."), examples=["Alex"])
    last_name: str = Field(max_length=150, description=_("User's family name."), examples=["Pro"])
    password: str = Field(min_length=8, max_length=128, description=_("Secure password chosen by the user."))


# ==============================================================================
# 3. МОДУЛЬ: ЛИЧНЫЙ КАБИНЕТ (ME)
# ==============================================================================

class UserProfileResponseSchema(BaseModel):
    """Схема ответа, возвращающая полные данные профиля пользователя."""
    id: int = Field(description=_("Unique database identifier of the user."), examples=[42])
    email: EmailStr = Field(description=_("User's primary email address used for login."))
    first_name: Optional[str] = Field(default=None, max_length=150, description=_("User's given name."))
    last_name: Optional[str] = Field(default=None, max_length=150, description=_("User's family name."))
    role: GlobalRoleEnum = Field(description=_("Global system role determining baseline permissions."))
    avatar: Optional[str] = Field(default=None, description=_("Absolute URL to the user's avatar image."))
    is_active: bool = Field(description=_("Designates whether this user account should be treated as active."))
    date_joined: datetime = Field(description=_("Timestamp indicating when the user account was created."))


class UserProfileUpdateRequestSchema(BaseModel):
    """Схема запроса для частичного обновления (PATCH) профиля самим пользователем."""
    first_name: Optional[str] = Field(default=None, max_length=150, description=_("Updated given name."))
    last_name: Optional[str] = Field(default=None, max_length=150, description=_("Updated family name."))

    class Config:
        extra = "forbid"


# ==============================================================================
# 4. МОДУЛЬ: ОБЪЕКТНЫЕ ПРАВА ПРОЕКТОВ (GUARDIAN CONTEXT)
# ==============================================================================

class ProjectUserPermissionsSchema(BaseModel):
    """Схема, описывающая текущие права конкретного пользователя внутри проекта."""
    user_id: int = Field(description=_("Unique database identifier of the user."), examples=[42])
    email: EmailStr = Field(description=_("User's email address."))
    permissions: List[ProjectPermissionEnum] = Field(description=_("List of assigned object-level permissions."))


class ProjectParticipantsListResponseSchema(BaseModel):
    """Схема ответа для получения списка всех участников проекта и их прав (GET)."""
    project_id: int = Field(description=_("ID of the project being queried."), examples=[12])
    users: List[ProjectUserPermissionsSchema] = Field(description=_("List of users in this project."))


class ProjectUserPermissionsSyncRequestSchema(BaseModel):
    """Схема запроса (PUT) для полной идемпотентной перезаписи прав пользователя на проект."""
    permissions: List[ProjectPermissionEnum] = Field(
        description=_("The exact list of permissions that should remain. Missing ones will be revoked."),
        examples=[[ProjectPermissionEnum.VIEW, ProjectPermissionEnum.EDIT]]
    )

    class Config:
        extra = "forbid"