from datetime import datetime
from enum import StrEnum
from typing import Annotated

from bson import ObjectId
from pydantic import BaseModel, BeforeValidator, EmailStr, Field


def validate_object_id(v) -> str:
    """Convert ObjectId to string"""
    if isinstance(v, ObjectId):
        return str(v)
    if isinstance(v, str):
        return v
    raise ValueError('Invalid ObjectId')


PyObjectId = Annotated[str, BeforeValidator(validate_object_id)]


class UserRole(StrEnum):
    CLIENT = "client"
    REVIEWER = "reviewer"
    LINGUIST = "linguist"
    PRODUCTION = "production"
    PROJECT_MANAGER = "project_manager"
    ADMIN = "admin"


class AuthProvider(StrEnum):
    LOCAL = "local"
    MICROSOFT = "microsoft"


class User(BaseModel):
    id: PyObjectId | None = Field(None, alias="_id")
    email: EmailStr
    hashed_password: str | None = None  # Optional for Microsoft users
    full_name: str
    role: UserRole = UserRole.CLIENT
    auth_provider: AuthProvider = AuthProvider.LOCAL
    is_active: bool = True
    pm_client_ids: list[str] = []  # Client IDs where this user is Project Manager (admin-assigned)
    languages: list[str] = []  # BCP-47 language codes the user is competent in (R-8)
    created_at: datetime | None = None
    updated_at: datetime | None = None

    class Config:
        populate_by_name = True
        use_enum_values = True


class UserInDB(User):
    pass


class UserCreate(BaseModel):
    email: EmailStr
    password: str
    full_name: str
    role: UserRole = UserRole.CLIENT


class UserUpdate(BaseModel):
    email: EmailStr | None = None
    full_name: str | None = None
    role: UserRole | None = None
    is_active: bool | None = None
    pm_client_ids: list[str] | None = None
    languages: list[str] | None = None
