from datetime import datetime
from enum import Enum
from typing import Optional, Annotated

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


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(str, Enum):
    CLIENT = "client"
    REVIEWER = "reviewer"
    PRODUCTION = "production"
    ADMIN = "admin"


class AuthProvider(str, Enum):
    LOCAL = "local"
    MICROSOFT = "microsoft"


class User(BaseModel):
    id: Optional[PyObjectId] = Field(None, alias="_id")
    email: EmailStr
    hashed_password: Optional[str] = None  # Optional for Microsoft users
    full_name: str
    role: UserRole = UserRole.CLIENT
    auth_provider: AuthProvider = AuthProvider.LOCAL
    is_active: bool = True
    created_at: Optional[datetime] = None
    updated_at: Optional[datetime] = 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: Optional[EmailStr] = None
    full_name: Optional[str] = None
    role: Optional[UserRole] = None
    is_active: Optional[bool] = None
