import uuid
from datetime import datetime, date

from pydantic import BaseModel, EmailStr, Field, model_validator

from app.models.user import AuthProvider, UserRole


PERSONNEL_NUMBER_PATTERN = r"^[0-9]+$"


class UserOut(BaseModel):
    model_config = {"from_attributes": True}

    id: uuid.UUID
    company_id: uuid.UUID | None
    department_id: uuid.UUID | None
    email: str
    first_name: str
    last_name: str
    full_name: str
    role: UserRole
    auth_provider: AuthProvider
    is_active: bool
    last_login: datetime | None
    created_at: datetime
    kuerzel: str | None = None
    personnel_number: str | None = None
    can_manual_time_entry: bool = False
    work_schedule_id: uuid.UUID | None = None
    entry_date: date | None = None
    exit_date: date | None = None
    anonymized_at: datetime | None = None


class NotificationTypeOut(BaseModel):
    key: str
    label: str
    enabled: bool


class NotificationPrefsUpdate(BaseModel):
    prefs: dict[str, bool]


class UserUpdate(BaseModel):
    first_name: str | None = Field(None, min_length=1, max_length=100)
    last_name: str | None = Field(None, min_length=1, max_length=100)
    department_id: uuid.UUID | None = None
    role: UserRole | None = None
    work_schedule_id: uuid.UUID | None = None
    kuerzel: str | None = Field(None, max_length=20)
    personnel_number: str | None = Field(None, max_length=50, pattern=PERSONNEL_NUMBER_PATTERN)
    can_manual_time_entry: bool | None = None
    is_active: bool | None = None
    entry_date: date | None = None
    exit_date: date | None = None


class InviteRequest(BaseModel):
    email: EmailStr
    first_name: str = Field(min_length=1, max_length=100)
    last_name: str = Field(min_length=1, max_length=100)
    role: UserRole = UserRole.EMPLOYEE
    department_id: uuid.UUID | None = None
    personnel_number: str | None = Field(None, max_length=50, pattern=PERSONNEL_NUMBER_PATTERN)
    # Wenn gesetzt → User wird sofort aktiv (kein Invite-E-Mail nötig)
    initial_password: str | None = Field(None, min_length=8, max_length=128)

    @model_validator(mode="after")
    def password_strength(self):
        pw = self.initial_password
        if pw is None:
            return self
        if not any(c.isupper() for c in pw):
            raise ValueError("initial_password must contain at least one uppercase letter")
        if not any(c.isdigit() for c in pw):
            raise ValueError("initial_password must contain at least one digit")
        return self


class InviteAccept(BaseModel):
    token: str
    password: str = Field(min_length=8, max_length=128)

    @model_validator(mode="after")
    def password_strength(self):
        pw = self.password
        if not any(c.isupper() for c in pw):
            raise ValueError("Password must contain at least one uppercase letter")
        if not any(c.isdigit() for c in pw):
            raise ValueError("Password must contain at least one digit")
        return self


class UserListResponse(BaseModel):
    total: int
    items: list[UserOut]


class SetKioskPinRequest(BaseModel):
    pin: str = Field(min_length=4, max_length=6, pattern=r"^\d+$")


class SetKioskNfcUidRequest(BaseModel):
    """UID des NFC-Chips (roh, wie vom Reader geliefert - z.B. dezimale EM4100-ID
    oder Mifare-Hex-UID). Nur Admin/HR - Mitarbeiter setzen ihre eigene Karte nicht
    selbst, da sonst jeder eine fremde UID eintragen könnte."""
    nfc_uid: str | None = Field(None, min_length=1, max_length=64)


class NextPersonnelNumberResponse(BaseModel):
    next: str


class UserImportRowError(BaseModel):
    row: int
    email: str | None = None
    message: str


class UserImportRowResult(BaseModel):
    row: int
    email: str
    personnel_number: str | None = None
    action: str  # "created" | "reactivated" | "skipped" | "error"
    message: str | None = None


class UserImportResult(BaseModel):
    total_rows: int
    created: int
    reactivated: int
    errors: int
    items: list[UserImportRowResult]
