from typing import Annotated, Optional
from pydantic import BaseModel, ConfigDict, Field, field_validator, BeforeValidator
from datetime import datetime

StrId = Annotated[str, BeforeValidator(str)]


class JobtypeBase(BaseModel):
    name: str = Field(..., max_length=100)
    description: Optional[str] = None
    is_active: bool = True

    @field_validator("name")
    @classmethod
    def validate_name(cls, v):
        if v is None:
            return v
        v = v.strip()
        if len(v) < 1:
            raise ValueError("Name must be at least 1 character")
        return v


class JobtypeCreate(JobtypeBase):
    pass


class JobtypeUpdate(BaseModel):
    name: Optional[str] = Field(None, max_length=100)
    description: Optional[str] = None
    is_active: Optional[bool] = None

    @field_validator("name")
    @classmethod
    def validate_name(cls, v):
        if v is None:
            return v
        v = v.strip()
        if len(v) < 1:
            raise ValueError("Name must be at least 1 character")
        return v


class JobtypeResponse(BaseModel):
    id: StrId
    name: str
    description: Optional[str]
    is_active: bool
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class JobstatusBase(BaseModel):
    name: str = Field(..., max_length=100)
    description: Optional[str] = None
    display_order: int = 0
    is_active: bool = True

    @field_validator("name")
    @classmethod
    def validate_name(cls, v):
        if v is None:
            return v
        v = v.strip()
        if len(v) < 1:
            raise ValueError("Name must be at least 1 character")
        return v


class JobstatusCreate(JobstatusBase):
    pass


class JobstatusUpdate(BaseModel):
    name: Optional[str] = Field(None, max_length=100)
    description: Optional[str] = None
    display_order: Optional[int] = None
    is_active: Optional[bool] = None

    @field_validator("name")
    @classmethod
    def validate_name(cls, v):
        if v is None:
            return v
        v = v.strip()
        if len(v) < 1:
            raise ValueError("Name must be at least 1 character")
        return v


class JobstatusResponse(BaseModel):
    id: StrId
    name: str
    description: Optional[str]
    display_order: int
    is_active: bool
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class JobpriorityBase(BaseModel):
    name: str = Field(..., max_length=100)
    level: int
    color: Optional[str] = Field(None, max_length=7)
    is_active: bool = True

    @field_validator("name")
    @classmethod
    def validate_name(cls, v):
        if v is None:
            return v
        v = v.strip()
        if len(v) < 1:
            raise ValueError("Name must be at least 1 character")
        return v

    @field_validator("color")
    @classmethod
    def validate_color(cls, v):
        if v is None:
            return v
        v = v.strip()
        if v and not v.startswith("#"):
            raise ValueError("Color must start with #")
        if v and len(v) != 7:
            raise ValueError("Color must be in format #RRGGBB")
        return v


class JobpriorityCreate(JobpriorityBase):
    pass


class JobpriorityUpdate(BaseModel):
    name: Optional[str] = Field(None, max_length=100)
    level: Optional[int] = None
    color: Optional[str] = Field(None, max_length=7)
    is_active: Optional[bool] = None

    @field_validator("name")
    @classmethod
    def validate_name(cls, v):
        if v is None:
            return v
        v = v.strip()
        if len(v) < 1:
            raise ValueError("Name must be at least 1 character")
        return v

    @field_validator("color")
    @classmethod
    def validate_color(cls, v):
        if v is None:
            return v
        v = v.strip()
        if v and not v.startswith("#"):
            raise ValueError("Color must start with #")
        if v and len(v) != 7:
            raise ValueError("Color must be in format #RRGGBB")
        return v


class JobpriorityResponse(BaseModel):
    id: StrId
    name: str
    level: int
    color: Optional[str]
    is_active: bool
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class TagBase(BaseModel):
    name: str = Field(..., max_length=100)
    color: Optional[str] = Field(None, max_length=7)

    @field_validator("name")
    @classmethod
    def validate_name(cls, v):
        if v is None:
            return v
        v = v.strip()
        if len(v) < 1:
            raise ValueError("Name must be at least 1 character")
        return v

    @field_validator("color")
    @classmethod
    def validate_color(cls, v):
        if v is None:
            return v
        v = v.strip()
        if v and not v.startswith("#"):
            raise ValueError("Color must start with #")
        if v and len(v) != 7:
            raise ValueError("Color must be in format #RRGGBB")
        return v


class TagCreate(TagBase):
    pass


class TagUpdate(BaseModel):
    name: Optional[str] = Field(None, max_length=100)
    color: Optional[str] = Field(None, max_length=7)

    @field_validator("name")
    @classmethod
    def validate_name(cls, v):
        if v is None:
            return v
        v = v.strip()
        if len(v) < 1:
            raise ValueError("Name must be at least 1 character")
        return v

    @field_validator("color")
    @classmethod
    def validate_color(cls, v):
        if v is None:
            return v
        v = v.strip()
        if v and not v.startswith("#"):
            raise ValueError("Color must start with #")
        if v and len(v) != 7:
            raise ValueError("Color must be in format #RRGGBB")
        return v


class TagResponse(BaseModel):
    id: StrId
    name: str
    color: Optional[str]
    usage_count: int
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


from typing import List, 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)