from typing import List, Optional, Union

from pydantic import BaseModel, validator

from starlite.types import Scopes


class AllowedHostsConfig(BaseModel):
    """Configuration for allowed hosts protection.

    To enable allowed hosts protection, pass an instance of this class to the :class:`Starlite <starlite.app.Starlite>`
    constructor using the ``allowed_hosts`` key.
    """

    allowed_hosts: List[str] = ["*"]
    """A list of trusted hosts.

    Use ``*.`` to allow all hosts, or prefix domains with ``*.`` to allow all sub domains.
    """
    exclude: Optional[Union[str, List[str]]] = None
    """A pattern or list of patterns to skip in the Allowed Hosts middleware."""
    exclude_opt_key: Optional[str] = None
    """An identifier to use on routes to disable hosts check for a particular route."""
    scopes: Optional[Scopes] = None
    """ASGI scopes processed by the middleware, if None both ``http`` and ``websocket`` will be processed."""
    www_redirect: bool = True
    """A boolean dictating whether to redirect requests that start with ``www.`` and otherwise match a trusted host."""

    @validator("allowed_hosts", always=True)
    def validate_allowed_hosts(cls, value: List[str]) -> List[str]:  # pylint: disable=no-self-argument
        """Ensure that the trusted hosts have correct domain wildcards.

        Args:
            value: A list of trusted hosts.

        Returns:
            A list of trusted hosts.
        """
        for host in value:
            if host != "*" and "*" in host and not host.startswith("*."):
                raise ValueError(
                    "domain wildcards can only appear in the beginning of the domain, e.g. ``*.example.com``"
                )
        return value
