"""pinn owner 登录内网约束 — design v0.11 D15。"""

from __future__ import annotations

import ipaddress
from typing import Any


def _normalize_host(raw: str | None) -> str:
    if not raw:
        return ""
    host = str(raw).strip().lower()
    if host.startswith("[") and "]" in host:
        host = host[1 : host.index("]")]
    elif ":" in host and host.count(":") == 1:
        left, right = host.rsplit(":", 1)
        if right.isdigit():
            host = left
    return host


def is_private_host(host: str | None) -> bool:
    """RFC1918 · loopback · link-local · localhost。"""
    name = _normalize_host(host)
    if not name:
        return False
    if name in {"localhost", "127.0.0.1", "::1"}:
        return True
    if name.endswith(".local"):
        return True
    try:
        ip = ipaddress.ip_address(name)
    except ValueError:
        return False
    return bool(ip.is_private or ip.is_loopback or ip.is_link_local)


def owner_intranet_only(config: dict[str, Any]) -> bool:
    tenant_auth = config.get("tenant_auth") or {}
    if not isinstance(tenant_auth, dict):
        return False
    return bool(tenant_auth.get("owner_intranet_only", False))


def owner_login_host_allowed(host: str | None, config: dict[str, Any]) -> bool:
    if not owner_intranet_only(config):
        return True
    name = _normalize_host(host)
    if not name:
        return False
    tenant_auth = config.get("tenant_auth") or {}
    extra = tenant_auth.get("owner_intranet_hosts") or []
    if isinstance(extra, list):
        allowed = {_normalize_host(str(item)) for item in extra if str(item).strip()}
        if name in allowed:
            return True
    return is_private_host(name)


def client_ip_private(client_host: str | None) -> bool:
    if not client_host:
        return False
    try:
        ip = ipaddress.ip_address(str(client_host).strip())
    except ValueError:
        return False
    return bool(ip.is_private or ip.is_loopback or ip.is_link_local)


def is_desktop_agent_request(*, agent_header: str | None) -> bool:
    """客户端 Agent 登录 — 可经公网 HTTPS 调 API，非浏览器 Console。"""
    token = str(agent_header or "").strip().lower()
    return token in {"desktop", "client", "1", "true", "owner-client"}


def owner_login_client_allowed(client_host: str | None, config: dict[str, Any]) -> bool:
    if not owner_intranet_only(config):
        return True
    return client_ip_private(client_host)


def owner_console_login_allowed(
    *,
    host: str | None,
    client_host: str | None,
    config: dict[str, Any],
    from_desktop_agent: bool,
) -> tuple[bool, str | None]:
    """浏览器 Console 须内网；桌面 Agent 可公网 + api_token。"""
    if from_desktop_agent:
        return True, None
    if not owner_intranet_only(config):
        return True, None
    if not owner_login_host_allowed(host, config):
        return False, "owner_login_intranet_only"
    if not owner_login_client_allowed(client_host, config):
        return False, "owner_login_intranet_only"
    return True, None
