from pydantic import BaseModel, Field, EmailStr, field_validator, model_validator
from typing import Optional
from datetime import datetime
import re


class AccountSummaryResponse(BaseModel):
    id: int
    uin: str
    name: str
    email: Optional[str] = None
    phone: Optional[str] = None
    is_active: bool
    active_provider: Optional[str] = None

    class Config:
        from_attributes = True


_ALLOWED_CONTACT_TYPES = {"billing", "support", "technical", "general", "other"}


class ContactCreate(BaseModel):
    name: Optional[str] = Field(None, max_length=150)
    email: Optional[EmailStr] = None
    phone: Optional[str] = Field(None, max_length=30)
    contact_type: Optional[str] = Field(None, max_length=50)
    is_active: Optional[bool] = True
    title: Optional[str] = Field(None, max_length=255)
    dob: Optional[datetime] = None
    timezone: Optional[str] = Field(None, max_length=32)
    website: Optional[str] = Field(None, max_length=255)

    @field_validator("phone", mode="before")
    @classmethod
    def validate_phone(cls, v: Optional[str]) -> Optional[str]:
        if v is None or v == "":
            return v
        if not re.match(r'^[+\d\s\-(). ]{1,30}$', v):
            raise ValueError("phone contains invalid characters.")
        return v

    @field_validator("contact_type", mode="before")
    @classmethod
    def validate_contact_type(cls, v: Optional[str]) -> Optional[str]:
        if v is not None and v not in _ALLOWED_CONTACT_TYPES:
            raise ValueError(f"contact_type must be one of: {sorted(_ALLOWED_CONTACT_TYPES)}")
        return v


class ContactUpdate(ContactCreate):
    pass


class ContactResponse(BaseModel):
    id: int
    name: Optional[str] = None
    email: Optional[str] = None
    phone: Optional[str] = None
    contact_type: Optional[str] = None
    is_active: Optional[bool] = None
    title: Optional[str] = None
    dob: Optional[datetime] = None
    timezone: Optional[str] = None
    website: Optional[str] = None

    class Config:
        from_attributes = True


class LocationCreate(BaseModel):
    name: Optional[str] = None
    email: Optional[str] = None
    phone: Optional[str] = None
    location_type: Optional[str] = None
    is_active: Optional[bool] = True
    # Address fields
    address_line_1: Optional[str] = None
    address_line_2: Optional[str] = None
    zipcode: Optional[str] = None
    city: Optional[str] = None
    state: Optional[str] = None
    country: Optional[str] = None


class LocationUpdate(LocationCreate):
    pass


class LocationResponse(BaseModel):
    id: int
    name: Optional[str] = None
    email: Optional[str] = None
    phone: Optional[str] = None
    location_type: Optional[str] = None
    is_active: Optional[bool] = None
    # Flattened address fields
    address_line_1: Optional[str] = None
    address_line_2: Optional[str] = None
    zipcode: Optional[str] = None
    city: Optional[str] = None
    state: Optional[str] = None
    country: Optional[str] = None

    class Config:
        from_attributes = True

    @model_validator(mode="before")
    @classmethod
    def extract_address_fields(cls, obj):
        """Flatten the nested address relationship into top-level fields."""
        if hasattr(obj, "address") and obj.address is not None:
            addr = obj.address
            return {
                "id": obj.id,
                "name": obj.name,
                "email": obj.email,
                "phone": obj.phone,
                "location_type": obj.location_type,
                "is_active": obj.is_active,
                "address_line_1": addr.address_line_1,
                "address_line_2": addr.address_line_2,
                "zipcode": addr.zipcode,
                "city": addr.city,
                "state": addr.state,
                "country": addr.country,
            }
        return obj
