# @File: backend/services/uptimerobot/packages.py
# @Desc: CRUD helpers for monitoring packages. Validates allowed monitor
#        types and enforces slug uniqueness. Write paths are admin-only.
from __future__ import annotations

from typing import Iterable, List, Optional

from models.uptimerobot import UptimePackage
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession


_VALID_MONITOR_TYPES = {"http", "ping", "port", "keyword", "heartbeat"}


def normalize_allowed_types(raw: str) -> str:
    """Return a cleaned, validated csv of allowed monitor types."""
    if not raw:
        return "http"
    items = [p.strip().lower() for p in raw.split(",") if p.strip()]
    valid = [p for p in items if p in _VALID_MONITOR_TYPES]
    if not valid:
        return "http"
    # Deduplicate while preserving order.
    seen: set[str] = set()
    out: List[str] = []
    for v in valid:
        if v not in seen:
            seen.add(v)
            out.append(v)
    return ",".join(out)


def package_allows_type(package: UptimePackage, monitor_type: str) -> bool:
    allowed = {p.strip().lower() for p in (package.allowed_monitor_types or "").split(",") if p.strip()}
    return monitor_type.lower() in allowed


async def list_packages(session: AsyncSession, include_inactive: bool = True) -> List[UptimePackage]:
    stmt = select(UptimePackage).order_by(UptimePackage.id.asc())
    if not include_inactive:
        stmt = stmt.where(UptimePackage.is_active.is_(True))
    result = await session.execute(stmt)
    return list(result.scalars().all())


async def get_package(session: AsyncSession, package_id: int) -> Optional[UptimePackage]:
    return await session.get(UptimePackage, package_id)


async def get_package_by_slug(session: AsyncSession, slug: str) -> Optional[UptimePackage]:
    result = await session.execute(select(UptimePackage).where(UptimePackage.slug == slug))
    return result.scalar_one_or_none()


async def get_package_by_whmcs_product(
    session: AsyncSession, whmcs_product_id: int
) -> Optional[UptimePackage]:
    result = await session.execute(
        select(UptimePackage).where(UptimePackage.whmcs_product_id == whmcs_product_id)
    )
    return result.scalars().first()


def assert_interval_ok(package: UptimePackage, interval_seconds: int) -> None:
    if interval_seconds < package.min_check_interval:
        raise ValueError(
            f"Interval {interval_seconds}s is below the package minimum of "
            f"{package.min_check_interval}s."
        )


def assert_quota_ok(package: UptimePackage, used: int, *, limit_field: str) -> None:
    limit_attr = getattr(package, limit_field, 0)
    unlimited_flag = {
        "max_monitors": "monitors_unlimited",
        "max_alert_contacts": "alert_contacts_unlimited",
        "max_maintenance_windows": "maintenance_windows_unlimited",
        "max_status_pages": "status_pages_unlimited",
    }.get(limit_field)
    if unlimited_flag and bool(getattr(package, unlimited_flag, False)):
        return
    if used >= int(limit_attr):
        raise ValueError(
            f"Package '{package.name}' quota reached ({used}/{limit_attr})."
        )


def iter_package_summaries(packages: Iterable[UptimePackage]) -> List[dict]:
    return [
        {
            "id": p.id,
            "slug": p.slug,
            "name": p.name,
            "max_monitors": p.max_monitors,
            "monitors_unlimited": p.monitors_unlimited,
        }
        for p in packages
    ]