"""DNS Robot API client. Zero external dependencies."""

import json
import urllib.request
import urllib.parse
import urllib.error
from typing import Any, Dict, Optional


class DNSRobot:
    """Client for the DNS Robot API (https://dnsrobot.net).

    Provides access to 11 DNS and network tools including DNS lookups,
    WHOIS queries, SSL certificate checks, and email authentication
    validation (SPF, DKIM, DMARC).

    No API key required. Zero external dependencies.

    Example::

        from dnsrobot import DNSRobot

        dr = DNSRobot()
        result = dr.dns_lookup("example.com")
        print(result["resolvedIPs"])
    """

    def __init__(
        self,
        base_url: str = "https://dnsrobot.net/api",
        timeout: int = 30,
        user_agent: Optional[str] = None,
    ):
        self.base_url = base_url.rstrip("/")
        self.timeout = timeout
        from dnsrobot import __version__
        self.user_agent = user_agent or f"dnsrobot-python/{__version__}"

    def _post(self, endpoint: str, payload: Dict[str, Any]) -> Dict[str, Any]:
        url = f"{self.base_url}/{endpoint}"
        data = json.dumps(payload).encode("utf-8")
        req = urllib.request.Request(
            url,
            data=data,
            headers={
                "Content-Type": "application/json",
                "User-Agent": self.user_agent,
            },
            method="POST",
        )
        try:
            with urllib.request.urlopen(req, timeout=self.timeout) as resp:
                return json.loads(resp.read().decode("utf-8"))
        except urllib.error.HTTPError as e:
            body = e.read().decode("utf-8", errors="replace")
            raise RuntimeError(f"DNS Robot API error: HTTP {e.code} from {endpoint}: {body}") from e
        except urllib.error.URLError as e:
            raise RuntimeError(f"DNS Robot API connection error: {e.reason}") from e

    def _get(self, endpoint: str, params: Dict[str, Any]) -> Dict[str, Any]:
        query = urllib.parse.urlencode(params)
        url = f"{self.base_url}/{endpoint}?{query}"
        req = urllib.request.Request(url, headers={"User-Agent": self.user_agent})
        try:
            with urllib.request.urlopen(req, timeout=self.timeout) as resp:
                return json.loads(resp.read().decode("utf-8"))
        except urllib.error.HTTPError as e:
            body = e.read().decode("utf-8", errors="replace")
            raise RuntimeError(f"DNS Robot API error: HTTP {e.code} from {endpoint}: {body}") from e
        except urllib.error.URLError as e:
            raise RuntimeError(f"DNS Robot API connection error: {e.reason}") from e

    def dns_lookup(
        self,
        domain: str,
        record_type: str = "A",
        dns_server: str = "8.8.8.8",
    ) -> Dict[str, Any]:
        """Perform a DNS lookup.

        Args:
            domain: Domain name to look up.
            record_type: Record type (A, AAAA, MX, TXT, CNAME, NS, SOA, etc.).
            dns_server: DNS server to query.

        Returns:
            Dict with resolvedIPs, recordType, responseTime, etc.

        See https://dnsrobot.net/dns-lookup
        """
        if not domain:
            raise ValueError("domain is required")
        return self._post("dns-query", {
            "domain": domain,
            "recordType": record_type,
            "dnsServer": dns_server,
        })

    def whois_lookup(self, domain: str) -> Dict[str, Any]:
        """Retrieve WHOIS registration data.

        Args:
            domain: Domain name to look up.

        Returns:
            Dict with registrar, dates, nameservers, status, etc.

        See https://dnsrobot.net/whois-lookup
        """
        if not domain:
            raise ValueError("domain is required")
        return self._post("whois", {"domain": domain})

    def ssl_check(self, domain: str) -> Dict[str, Any]:
        """Check SSL/TLS certificate.

        Args:
            domain: Domain to check.

        Returns:
            Dict with leafCertificate, certificateChain, etc.

        See https://dnsrobot.net/ssl-checker
        """
        if not domain:
            raise ValueError("domain is required")
        return self._post("ssl-certificate", {"domain": domain})

    def spf_check(self, domain: str) -> Dict[str, Any]:
        """Validate SPF record.

        Args:
            domain: Domain to check.

        Returns:
            Dict with found, rawRecord, mechanisms, grade, score, warnings.

        See https://dnsrobot.net/spf-checker
        """
        if not domain:
            raise ValueError("domain is required")
        return self._post("spf-checker", {"domain": domain})

    def dkim_check(self, domain: str, selector: Optional[str] = None) -> Dict[str, Any]:
        """Check DKIM record.

        Args:
            domain: Domain to check.
            selector: DKIM selector (optional, common selectors tried if omitted).

        Returns:
            Dict with found, selector, grade, keyType, keySize, etc.

        See https://dnsrobot.net/dkim-checker
        """
        if not domain:
            raise ValueError("domain is required")
        payload: Dict[str, Any] = {"domain": domain}
        if selector:
            payload["selector"] = selector
        return self._post("dkim-checker", payload)

    def dmarc_check(self, domain: str) -> Dict[str, Any]:
        """Validate DMARC record.

        Args:
            domain: Domain to check.

        Returns:
            Dict with found, rawRecord, policy, subdomainPolicy, grade, warnings.

        See https://dnsrobot.net/dmarc-checker
        """
        if not domain:
            raise ValueError("domain is required")
        return self._post("dmarc-checker", {"domain": domain})

    def mx_lookup(self, domain: str) -> Dict[str, Any]:
        """Retrieve MX records.

        Args:
            domain: Domain to look up.

        Returns:
            Dict with mxRecords (priority, exchange, IPs), summary.

        See https://dnsrobot.net/mx-lookup
        """
        if not domain:
            raise ValueError("domain is required")
        return self._post("mx-lookup", {"domain": domain})

    def ns_lookup(self, domain: str) -> Dict[str, Any]:
        """Retrieve nameserver records.

        Args:
            domain: Domain to look up.

        Returns:
            Dict with nameservers, response times, IPs.

        See https://dnsrobot.net/ns-lookup
        """
        if not domain:
            raise ValueError("domain is required")
        return self._post("ns-lookup", {"domain": domain})

    def ip_lookup(self, ip: str) -> Dict[str, Any]:
        """Look up IP geolocation data.

        Args:
            ip: IP address to look up.

        Returns:
            Dict with city, country, isp, org, as, timezone, etc.

        See https://dnsrobot.net/ip-lookup
        """
        if not ip:
            raise ValueError("ip is required")
        return self._post("ip-info", {"ip": ip})

    def http_headers(self, url: str) -> Dict[str, Any]:
        """Fetch and analyze HTTP response headers.

        Args:
            url: URL to check (https:// prefix added if missing).

        Returns:
            Dict with headers, statusCode, security grade, etc.

        See https://dnsrobot.net/http-headers
        """
        if not url:
            raise ValueError("url is required")
        if not url.startswith(("http://", "https://")):
            url = f"https://{url}"
        return self._post("http-headers", {"url": url})

    def port_check(self, host: str, port: int) -> Dict[str, Any]:
        """Check if a TCP port is open.

        Args:
            host: Hostname or IP to check.
            port: Port number (1-65535).

        Returns:
            Dict with status (open/closed), ms, service.

        See https://dnsrobot.net/port-checker
        """
        if not host:
            raise ValueError("host is required")
        if not port:
            raise ValueError("port is required")
        return self._get("port-check", {"host": host, "port": port})
