from typing import Optional, List, Annotated
from pydantic import BaseModel, ConfigDict, Field, field_validator, EmailStr, BeforeValidator
from datetime import datetime
from utils.utils import UserRole

StrId = Annotated[str, BeforeValidator(str)]


# User Schemas
class UserBase(BaseModel):
    email: EmailStr = Field(..., max_length=255)
    first_name: str = Field(..., max_length=100)
    last_name: str = Field(..., max_length=100)
    role: UserRole
    department_id: Optional[str] = Field(None, max_length=36)
    phone: Optional[str] = Field(None, max_length=50)
    is_active: bool = True

    @field_validator("email")
    @classmethod
    def normalise_email(cls, v):
        if v is None:
            return v
        return v.strip().lower()

    @field_validator("first_name", "last_name")
    @classmethod
    def normalise_name(cls, v):
        if v is None:
            return v
        return v.strip()


class UserCreate(UserBase):
    password: str = Field(..., min_length=8, max_length=255)

    @field_validator("password")
    @classmethod
    def validate_password(cls, v):
        if v is None:
            return v
        if len(v) < 8:
            raise ValueError("Password must be at least 8 characters")
        if not any(c.isupper() for c in v):
            raise ValueError("Password must include at least one uppercase letter")
        if not any(c.islower() for c in v):
            raise ValueError("Password must include at least one lowercase letter")
        if not any(c.isdigit() for c in v):
            raise ValueError("Password must include at least one number")
        return v


class UserUpdate(BaseModel):
    email: Optional[EmailStr] = Field(None, max_length=255)
    first_name: Optional[str] = Field(None, max_length=100)
    last_name: Optional[str] = Field(None, max_length=100)
    role: Optional[UserRole] = None
    department_id: Optional[str] = Field(None, max_length=36)
    phone: Optional[str] = Field(None, max_length=50)
    is_active: Optional[bool] = None

    @field_validator("email")
    @classmethod
    def normalise_email(cls, v):
        if v is None:
            return v
        return v.strip().lower()

    @field_validator("first_name", "last_name")
    @classmethod
    def normalise_name(cls, v):
        if v is None:
            return v
        return v.strip()


class UserResponse(BaseModel):
    id: StrId
    email: str
    first_name: str
    last_name: str
    role: UserRole
    department_id: Optional[StrId]
    phone: Optional[str]
    is_active: bool
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class DepartmentSummary(BaseModel):
    id: StrId
    name: str

    model_config = ConfigDict(from_attributes=True)


class TeamSummary(BaseModel):
    id: StrId
    name: str
    department: DepartmentSummary

    model_config = ConfigDict(from_attributes=True)


class UserTeamSummary(BaseModel):
    id: StrId
    team: TeamSummary
    created_at: datetime

    model_config = ConfigDict(from_attributes=True)


class UserDetailResponse(BaseModel):
    id: StrId
    email: str
    first_name: str
    last_name: str
    role: UserRole
    department_id: Optional[StrId]
    phone: Optional[str]
    is_active: bool
    created_at: datetime
    updated_at: datetime
    department: Optional[DepartmentSummary]
    user_teams: List[UserTeamSummary]

    model_config = ConfigDict(from_attributes=True)


# Notification Schemas
class NotificationBase(BaseModel):
    user_id: str = Field(..., max_length=36)
    notification_type: str = Field(..., max_length=100)
    title: str = Field(..., max_length=500)
    message: str
    related_entity_type: Optional[str] = Field(None, max_length=100)
    related_entity_id: Optional[str] = Field(None, max_length=36)
    is_read: bool = False


class NotificationCreate(NotificationBase):
    pass


class NotificationUpdate(BaseModel):
    notification_type: Optional[str] = Field(None, max_length=100)
    title: Optional[str] = Field(None, max_length=500)
    message: Optional[str] = None
    related_entity_type: Optional[str] = Field(None, max_length=100)
    related_entity_id: Optional[str] = Field(None, max_length=36)
    is_read: Optional[bool] = None


class NotificationResponse(BaseModel):
    id: StrId
    user_id: StrId
    notification_type: str
    title: str
    message: str
    related_entity_type: Optional[str]
    related_entity_id: Optional[StrId]
    is_read: bool
    read_at: Optional[datetime]
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class UserSummary(BaseModel):
    id: StrId
    first_name: str
    last_name: str
    email: str

    model_config = ConfigDict(from_attributes=True)


class NotificationDetailResponse(BaseModel):
    id: StrId
    user_id: StrId
    notification_type: str
    title: str
    message: str
    related_entity_type: Optional[str]
    related_entity_id: Optional[StrId]
    is_read: bool
    read_at: Optional[datetime]
    created_at: datetime
    updated_at: datetime
    user: UserSummary

    model_config = ConfigDict(from_attributes=True)


# Paginated Response
from typing import Generic, TypeVar

T = TypeVar("T")


class PaginatedResponse(BaseModel, Generic[T]):
    items: List[T]
    total: int
    limit: int
    offset: int

    model_config = ConfigDict(from_attributes=True)