from typing import Dict, List, Any

from dns import resolver, exception


def resolve_cname(hostname: str) -> List[str]:
    """Resolve CNAME records for a hostname and return targets without trailing dots.

    If there is no CNAME record, this returns an empty list.
    Raises dns.exception.DNSException on resolver errors.
    """
    answers = resolver.resolve(hostname, "CNAME")
    targets: List[str] = []
    for rdata in answers:
        # rdata.target may be a Name object; to_text() yields with trailing dot
        target = getattr(rdata, "target", None)
        if target is None:
            # some dnspython versions use .to_text() directly on rdata
            text = rdata.to_text()
        else:
            text = target.to_text()
        targets.append(text.rstrip("."))
    return targets


def check_cname_map(cname_map: Dict[str, str]) -> List[Dict[str, Any]]:
    """Check a mapping of hostname -> expected CNAME target.

    Returns a list of result dicts: {
      'hostname': str,
      'expected': str,
      'actual': List[str],
      'ok': bool,
      'error': Optional[str]
    }
    """
    results: List[Dict[str, Any]] = []
    for hostname, expected in cname_map.items():
        expected_norm = expected.rstrip(".").lower()
        try:
            actual_targets = resolve_cname(hostname)
            actual_norm = [t.lower() for t in actual_targets]
            ok = expected_norm in actual_norm
            results.append({
                "hostname": hostname,
                "expected": expected,
                "actual": actual_targets,
                "ok": ok,
                "error": None,
            })
        except exception.DNSException as e:
            results.append({
                "hostname": hostname,
                "expected": expected,
                "actual": [],
                "ok": False,
                "error": str(e),
            })
    return results


def bytes_to_gb(num_bytes: int) -> float:
    """Convert bytes to gigabytes (GB, 1024^3)."""
    return round(num_bytes / (1024 ** 3), 3)