"""Typed, immutable models for the Infomaniak Manager-API subsystem.

Frozen pydantic snapshots returned by a
:class:`~mgf.cloud.manager.base.ManagerApi` adapter — account line-items
(products), web hostings and their sites, and DNS records. Nothing here imports
an HTTP client or SDK; the adapter translates the Manager API's JSON into these
types (mirroring how :mod:`mgf.cloud.models` snapshots the OpenStack surface).
"""

from __future__ import annotations

from pydantic import BaseModel, ConfigDict

__all__ = [
    "STARTER_TYPE",
    "DnsRecord",
    "HostingSite",
    "Product",
    "WebHosting",
]

#: Infomaniak's free entry hosting tier — ships with a domain, runs PHP + serves
#: static files, but has **no SSH shell and no MySQL database**. Encoded here so
#: callers branch on :attr:`WebHosting.has_ssh`, not a magic string.
STARTER_TYPE = "starter"


class _Frozen(BaseModel):
    model_config = ConfigDict(frozen=True)


class Product(_Frozen):
    """One line-item on the account — a hosting, domain, mailbox, cloud, etc."""

    id: int
    service_name: str
    customer_name: str = ""
    account_id: int | None = None


class WebHosting(_Frozen):
    """A web-hosting product (``service_name == "hosting"``).

    The tier that decides SSH/database availability is a *site* attribute
    (:attr:`HostingSite.hosting_type`), not present on this hosting object — so
    ask :meth:`~mgf.cloud.manager.base.ManagerApi.list_sites` and read
    :attr:`HostingSite.has_ssh`. A shallow hosting (from ``list_web_hostings``)
    carries only id + ``customer_name``; ``get_web_hosting`` fills the rest.
    """

    id: int
    account_id: int
    customer_name: str = ""
    version: int = 0
    is_free: bool = False
    is_zero_price: bool = False


class HostingSite(_Frozen):
    """One site served by a web hosting — its fqdn, doc-root, SSL state, tier."""

    id: int
    hosting_id: int
    main_fqdn: str = ""
    directory: str = "/"
    hosting_type: str = ""
    ssl_status: str = ""
    can_install_applications: bool = False

    @property
    def is_starter(self) -> bool:
        """True for Infomaniak's free Starter tier."""
        return self.hosting_type == STARTER_TYPE

    @property
    def has_ssh(self) -> bool:
        """Whether the tier offers SSH/SFTP shell access."""
        return bool(self.hosting_type) and not self.is_starter


class DnsRecord(_Frozen):
    """One record in a domain's DNS zone."""

    id: str
    source: str
    type: str
    ttl: int = 0
    target: str = ""
