from pydantic import BaseModel, Field, EmailStr, field_validator, ConfigDict
from typing import List, Optional
from bson import ObjectId
from datetime import datetime


class MongoBaseModel(BaseModel):
  id: Optional[str] = Field(
      default_factory=lambda: str(ObjectId()), alias="_id")

  model_config = ConfigDict(
      populate_by_name=True,
      arbitrary_types_allowed=True,
      json_encoders={ObjectId: str}
  )

  @field_validator('id', mode='before')
  @classmethod
  def convert_object_id_to_string(cls, v):
    if isinstance(v, ObjectId):
      return str(v)
    return v


class Item(MongoBaseModel):
  name: str
  price: float
  quantity: int
  unit: str
  related_items: List[str] = []


class OrderItem(BaseModel):
  item_id: str
  quantity: int
  price_at_order: float
  
  @field_validator("item_id")
  def validate_id(cls, v):
    if isinstance(v, ObjectId):
      return str(v)
    return v


class Order(MongoBaseModel):
  user_id: str
  items: List[OrderItem]
  total_amount: float
  payment_method: Optional[str] = None
  payment_status: str = "pending"
  order_status: str = "created"
  created_at: datetime = Field(default_factory=datetime.utcnow)
  updated_at: Optional[datetime] = None
  discount_applied: Optional[float] = None
  notes: Optional[str] = None

  # @field_validator("user_id")
  # def validate_user_id(cls, v):
  #   return validate_object_id(v)

  # @validator("order_status")
  # def valid_order_status(cls, v):
  #   allowed_statuses = ["created", "processing",
  #                       "shipped", "delivered", "cancelled"]
  #   if v not in allowed_statuses:
  #     raise ValueError(f"Invalid order status. Must be one of: {
  #                      ', '.join(allowed_statuses)}")
  #   return v

  # @validator("payment_status")
  # def valid_payment_status(cls, v):
  #   allowed_statuses = ["pending", "paid", "refunded", "failed"]
  #   if v not in allowed_statuses:
  #     raise ValueError(f"Invalid payment status. Must be one of: {
  #                      ', '.join(allowed_statuses)}")
  #   return v


class UserBase(BaseModel):
  username: str
  email: EmailStr
  full_name: str
  is_active: bool = True
  is_superuser: bool = False


class UserCreate(UserBase):
  password: str


class UserInDB(UserBase, MongoBaseModel):
  hashed_password: str


class User(UserBase, MongoBaseModel):
  pass


class Token(BaseModel):
  access_token: str
  token_type: str


class TokenData(BaseModel):
  username: Optional[str] = None
