#!/usr/bin/env python3
"""Host-shell/direct-route HTTPS GET through Static; credentials go to curl on stdin."""
import os
import subprocess
import sys
from urllib.parse import urlsplit


class IPCheckBearerError(ValueError):
    """The public IP check must never receive destination credentials."""


def config_quote(value):
    if any(ord(c) < 32 or ord(c) == 127 for c in value):
        raise ValueError("Control characters are not allowed")
    return '"' + value.replace('\\', '\\\\').replace('"', '\\"') + '"'


def build_config(proxy, target, bearer=None, auth_host=None):
    p, t = urlsplit(proxy), urlsplit(target)
    if (p.scheme != "http" or not p.hostname or not p.username
            or not p.password or p.path not in ("", "/") or p.query or p.fragment):
        raise ValueError("Expected the authenticated Static HTTP proxy URL")
    if (t.scheme != "https" or not t.hostname or t.username or t.password
            or t.fragment):
        raise ValueError("Expected an HTTPS destination without URL credentials")
    auth = []
    if bearer:
        if t.hostname.lower() == "ip.quotaguard.com":
            raise IPCheckBearerError("Destination bearer is not allowed for the IP check")
        if (not auth_host or t.hostname.lower() != auth_host.lower()
                or t.port not in (None, 443)):
            raise ValueError("Destination credential requires its approved HTTPS host")
        auth = ["header = " + config_quote("Authorization: Bearer " + bearer)]
    return "\n".join([
        "proxy = " + config_quote(proxy),
        "url = " + config_quote(target),
        'noproxy = ""',
        'proto = "=https"',
        "connect-timeout = 10", "max-time = 30",
        "silent", "show-error", "fail", "globoff",
        "write-out = " + config_quote(r"\nQG_STATUS %{http_connect} %{response_code}\n"),
    ] + auth + ["\n"])


def main():
    try:
        config = build_config(os.environ["QUOTAGUARDSTATIC_URL"],
                              os.environ["QG_TARGET_URL"],
                              os.environ.get("QG_DESTINATION_BEARER"),
                              os.environ.get("QG_AUTH_HOST"))
        # -q must be first: ignore ~/.curlrc, including redirects or tracing.
        # Capture failures; do not print raw stderr, URLs, or response bodies.
        result = subprocess.run(["curl", "-q", "--config", "-"],
                                input=config, text=True, capture_output=True,
                                timeout=35, check=False)
    except IPCheckBearerError:
        print("IP check rejects QG_DESTINATION_BEARER. Run: "
              "env -u QG_DESTINATION_BEARER QG_TARGET_URL=https://ip.quotaguard.com "
              "python3 qg_get.py", file=sys.stderr)
        return 2
    except (KeyError, ValueError):
        print("Missing or invalid proxy/destination configuration", file=sys.stderr)
        return 2
    except (OSError, subprocess.TimeoutExpired):
        print("curl unavailable or request timed out", file=sys.stderr)
        return 2
    body, marker, status = result.stdout.rpartition("\nQG_STATUS ")
    codes = status.strip().split()
    valid_status = (bool(marker) and len(codes) == 2
                    and all(len(code) == 3 and code.isascii() and code.isdigit() for code in codes))
    connect, response = map(int, codes) if valid_status else (None, None)
    if result.returncode:
        hints = {
            5: "Proxy DNS lookup failed; check the assigned hostname and permitted DNS/network route.",
            6: "Host DNS lookup failed; check hostname and resolver/network policy.",
            7: "Connection failed; check proxy host/port, reachability and network policy.",
            22: "HTTP error (400 or higher); confirm whether the proxy or destination rejected it. Check authentication and policy.",
            28: "Request timed out; check reachability, network policy and upstream availability.",
            35: "TLS handshake failed; check client transport and approved CA configuration.",
            56: "Receive or CONNECT failure; possible proxy rejection, policy denial or connection interruption. Exit code alone cannot identify the cause.",
            60: "TLS certificate verification failed; check approved CA trust. Do not disable verification.",
        }
        hint = hints.get(result.returncode, "Check the requesting client and permitted route with sanitized diagnostics.")
        detail = ""
        if valid_status:
            detail = f" CONNECT HTTP {connect:03d}; destination HTTP {response:03d} (000 = not reported)."
            if connect == 407:
                hint = "Proxy authentication rejected; check assigned connection credentials privately."
            elif connect >= 400:
                hint = "Proxy rejected CONNECT; check its authentication and policy."
            elif 200 <= connect < 300 and response >= 400:
                hint = "Destination returned an HTTP error after CONNECT; check its authentication, scope and IP policy."
        print(f"Request failed (curl exit {result.returncode}).{detail} {hint}", file=sys.stderr)
        return result.returncode
    if not valid_status:
        print("curl status fields unavailable; request result not verified.", file=sys.stderr)
        return 2
    # Print only the expected IP-check response, never arbitrary API payloads.
    if os.environ["QG_TARGET_URL"] == "https://ip.quotaguard.com":
        print(body.strip())
    else:
        print("HTTPS GET succeeded; response body suppressed")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
