import ipaddress
import re
from urllib.parse import urlparse


DOMAIN_LABEL_RE = re.compile(r"^[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?$")
SYSTEM_USERNAME_RE = re.compile(r"^[a-z_][a-z0-9_-]{0,31}$")
DB_IDENTIFIER_RE = re.compile(r"^[A-Za-z0-9_]{1,64}$")
PHP_SIZE_RE = re.compile(r"^-?\d+[KMGkmg]?$")
PHP_PM_OPTIONS = {"ondemand", "dynamic", "static"}


def is_valid_domain_name(value):
    if not value:
        return False
    value = value.strip().lower()
    if len(value) > 253 or value.startswith(".") or value.endswith("."):
        return False
    labels = value.split(".")
    if len(labels) < 2:
        return False
    return all(DOMAIN_LABEL_RE.match(label) for label in labels)


def normalize_domain_name(value):
    if not value:
        return None
    value = value.strip().lower().rstrip(".")
    return value if is_valid_domain_name(value) else None


def is_valid_hostname(value):
    if not value:
        return False
    value = value.strip().rstrip(".")
    try:
        ipaddress.ip_address(value)
        return True
    except ValueError:
        pass
    if len(value) > 253:
        return False
    return all(DOMAIN_LABEL_RE.match(label) for label in value.split("."))


def is_valid_origin_host(value):
    if not value:
        return False
    host = value
    if value.startswith("["):
        end = value.find("]")
        if end == -1:
            return False
        host = value[1:end]
        rest = value[end + 1:]
        if rest and not re.fullmatch(r":\d{1,5}", rest):
            return False
    elif ":" in value:
        host, port = value.rsplit(":", 1)
        if not port.isdigit():
            return False
    return is_valid_hostname(host)


def is_valid_system_username(value):
    return bool(value and SYSTEM_USERNAME_RE.fullmatch(value.strip()))


def is_valid_db_identifier(value):
    return bool(value and DB_IDENTIFIER_RE.fullmatch(value.strip()))


def is_safe_external_url(value, allow_relative=False, block_internal=False):
    if not value:
        return False
    value = value.strip()
    if allow_relative and value.startswith("/"):
        return True
    parsed = urlparse(value)
    if parsed.scheme not in {"http", "https"} or not parsed.netloc:
        return False
    if block_internal:
        host = parsed.hostname
        if not host:
            return False
        try:
            ip = ipaddress.ip_address(host)
            if ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_reserved or ip.is_multicast:
                return False
        except ValueError:
            pass
    return True


def is_valid_php_size(value):
    return bool(value and PHP_SIZE_RE.fullmatch(str(value).strip()))


def is_valid_php_pm(value):
    return value in PHP_PM_OPTIONS
