from urllib.parse import urlsplit, urlunsplit

import httpx

from .model import Result


def _build_direct_ip_url(url: str, ip: str) -> tuple[str, str]:
    parsed = urlsplit(url)
    if not parsed.scheme or not parsed.netloc or not parsed.hostname:
        raise ValueError(f"Invalid url: {url}")

    host = parsed.hostname
    ip_host = f"[{ip}]" if ":" in ip and not ip.startswith("[") else ip
    direct_netloc = f"{ip_host}:{parsed.port}" if parsed.port else ip_host
    direct_url = urlunsplit(
        (parsed.scheme, direct_netloc, parsed.path, parsed.query, parsed.fragment)
    )
    return direct_url, host


async def request(url, headers, ip=None, timeout=10.0):
    transport = httpx.AsyncHTTPTransport(retries=0)
    req_headers = dict(headers or {})

    if ip is None:
        async with httpx.AsyncClient(
            http2=True,
            headers=req_headers,
            transport=transport,
            timeout=timeout,
        ) as client:
            try:
                response = await client.get(url)
                return Result(
                    status=response.status_code,
                    headers=response.headers,
                    ip="dns",
                    url=url,
                    body=response.content,
                )
            except Exception as e:
                return Result(err=e, ip="dns", url=url)

    try:
        direct_url, host = _build_direct_ip_url(url, ip)
    except Exception as e:
        return Result(err=e, ip=ip, url=url)

    req_headers["Host"] = host
    async with httpx.AsyncClient(
        http2=True,
        headers=req_headers,
        transport=transport,
        timeout=timeout,
        verify=False,
    ) as client:
        try:
            response = await client.get(direct_url)
            return Result(
                status=response.status_code,
                headers=response.headers,
                ip=ip,
                url=url,
                body=response.content,
            )
        except Exception as e:
            return Result(err=e, ip=ip, url=url)
