PHONE_RE = re.compile(r"^\+?[0-9][0-9 ()\-.]{4,30}$")


class PhoneIn(BaseModel):
    phone: str
    label: str = ""

    @field_validator("phone")
    @classmethod
    def valid_phone(cls, v):
        v = v.strip()
        if not PHONE_RE.match(v):
            raise ValueError("Invalid phone number format")
        return v


class PhonePatch(BaseModel):
    label: Optional[str] = None
    is_active: Optional[bool] = None


def _serialize(p: CompanyPhoneNumber) -> dict:
    return {
        "id": p.id,
        "label": p.label,
        "phone": p.phone,
        "is_active": bool(p.is_active),
        "use_count": p.use_count,
        "created_at": p.created_at.isoformat() if p.created_at else None,
    }


async def _get_own(db: AsyncSession, user: User, pid: int) -> CompanyPhoneNumber:
    p = await db.get(CompanyPhoneNumber, pid)
    if not p or p.user_id != user.id:
        raise HTTPException(status_code=404, detail="Phone number not found")
    return p


@router.get("/list")
async def list_phones(active_only: bool = Query(False),
                      search: str = Query(""),
===SUPP===
def _norm_reason(r: str) -> str:
    r = (r or "").strip().lower()
    if r == "complained":
        r = "complaint"
    return r if r in REASON_CHOICES else "manual"


class SuppressionIn(BaseModel):
    email: EmailStr
    reason: str = "manual"
    source: str = ""


class BulkEmails(BaseModel):
    emails: list[EmailStr]
    reason: str = "manual"


class CheckEmails(BaseModel):
    emails: list[EmailStr]


def _serialize(s: SuppressionEntry) -> dict:
    return {
        "id": s.id,
        "email": s.email,
        "reason": s.reason,
        "source": s.source,
        "campaign_id": s.campaign_id,
        "created_at": s.created_at.isoformat() if s.created_at else None,
    }


@router.get("/list")
async def list_suppression(search: str = Query(""),
===SET===
class SettingIn(BaseModel):
    key: str = Field(min_length=1, max_length=150)
    value: object = None
    category: str = "general"
    description: str = ""


class BatchSettingsIn(BaseModel):
    values: dict


# Known settings keys with validation constraints
SETTING_DEFS = {
    "amount_min": {"type": "float", "min": 0, "max": 100000, "default": cfg.AMOUNT_MIN,
                   "label": "Random amount minimum ($)", "category": "financial"},
    "amount_max": {"type": "float", "min": 0, "max": 100000, "default": cfg.AMOUNT_MAX,
                   "label": "Random amount maximum ($)", "category": "financial"},
    "shipping_min": {"type": "float", "min": 0, "max": 10000, "default": cfg.SHIPPING_MIN,
                     "label": "Random shipping minimum ($)", "category": "financial"},
    "shipping_max": {"type": "float", "min": 0, "max": 10000, "default": cfg.SHIPPING_MAX,
                     "label": "Random shipping maximum ($)", "category": "financial"},
    "invoice_format": {"type": "str", "max_len": 80, "default": cfg.INVOICE_NUMBER_FORMAT,
                       "label": "Invoice number format (tokens: {prefix},{R#},{r#},{d#},{seq4},{date},{hash})",
                       "category": "financial"},
    "invoice_prefix": {"type": "str", "max_len": 12, "default": "INV",
                       "label": "Invoice prefix", "category": "financial"},
    "default_daily_limit": {"type": "int", "min": 1, "max": 2000, "default": 500,
                            "label": "Default per-account daily send limit", "category": "limits"},
    "default_campaign_limit": {"type": "int", "min": 1, "max": 2000, "default": 200,
                               "label": "Default per-account per-campaign limit", "category": "limits"},
    "default_max_per_account": {"type": "int", "min": 1, "max": 2000, "default": 200,
                                "label": "Default max sends per account per campaign", "category": "limits"},
    "default_send_interval": {"type": "float", "min": 0.5, "max": 3600, "default": 1.0,
                              "label": "Default seconds between sends per account", "category": "limits"},
    "default_rate_per_minute": {"type": "int", "min": 1, "max": 600, "default": 60,
                                "label": "Default max sends per minute (per account)", "category": "limits"},
    "attachment_kind": {"type": "str", "max_len": 20, "default": "invoice",
                        "label": "Attachment filename prefix (invoice|order|receipt)",
                        "category": "attachments"},
    "unsubscribe_enabled": {"type": "bool", "default": True,
                            "label": "Enable unsubscribe links globally", "category": "compliance"},
    "unsubscribe_base_url": {"type": "str", "max_len": 300, "default": "",
                             "label": "Base URL for unsubscribe links (e.g. https://your-domain.com)",
                             "category": "compliance"},
    "company_name": {"type": "str", "max_len": 200, "default": "",
                     "label": "Company name for %CompanyName% default", "category": "general"},
    "test_email_default": {"type": "str", "max_len": 320, "default": "",
                           "label": "Default test email recipient", "category": "general"},
}


def _validate_value(key: str, value) -> tuple:
