import re
from typing import Annotated, List
from pydantic import BaseModel, EmailStr, Field, field_validator, ConfigDict, BeforeValidator
from datetime import datetime

StrId = Annotated[str, BeforeValidator(str)]


class SubmissionBase(BaseModel):
    name: str = Field(..., max_length=100)
    email: str = Field(..., max_length=254)

    @field_validator("name")
    @classmethod
    def validate_name(cls, v: str) -> str:
        if not v or not v.strip():
            raise ValueError("Name cannot be empty or whitespace only")
        if len(v.strip()) == 0:
            raise ValueError("Name must contain at least one non-whitespace character")
        return v.strip()

    @field_validator("email")
    @classmethod
    def validate_email(cls, v: str) -> str:
        v = v.strip().lower()
        pattern = r'^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'
        if not re.match(pattern, v):
            raise ValueError("Email must match valid email format")
        return v


class SubmissionCreate(SubmissionBase):
    pass


class SubmissionUpdate(BaseModel):
    name: str | None = Field(None, max_length=100)
    email: str | None = Field(None, max_length=254)

    @field_validator("name")
    @classmethod
    def validate_name(cls, v: str | None) -> str | None:
        if v is None:
            return v
        if not v or not v.strip():
            raise ValueError("Name cannot be empty or whitespace only")
        if len(v.strip()) == 0:
            raise ValueError("Name must contain at least one non-whitespace character")
        return v.strip()

    @field_validator("email")
    @classmethod
    def validate_email(cls, v: str | None) -> str | None:
        if v is None:
            return v
        v = v.strip().lower()
        pattern = r'^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'
        if not re.match(pattern, v):
            raise ValueError("Email must match valid email format")
        return v


class SubmissionResponse(BaseModel):
    id: StrId
    name: str
    email: str
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class SubmissionListResponse(BaseModel):
    items: List[SubmissionResponse]
    total: int
    limit: int
    offset: int

    model_config = ConfigDict(from_attributes=True)