#!/usr/bin/env python3
"""Secure API call helper for Python Requests.

This script demonstrates production-oriented HTTPS requests with TLS verification
enabled by default, optional custom CA bundle support, and safe error handling.

Examples:
  python secure_api_call.py https://api.example.com/v1/status
  python secure_api_call.py https://internal-api.example.local/v1/status --ca-bundle /etc/pki/internal-ca.pem
  python secure_api_call.py https://api.example.com/v1/status --timeout 15
"""

from __future__ import annotations

import argparse
import json
import sys
from typing import Any, Optional

import requests
from requests import Response, Session
from requests.exceptions import RequestException, SSLError


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Make a secure HTTPS API call with Python Requests and TLS verification."
    )
    parser.add_argument(
        "url",
        help="HTTPS URL to request. Example: https://api.example.com/v1/status",
    )
    parser.add_argument(
        "--method",
        default="GET",
        choices=["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"],
        help="HTTP method to use. Default: GET",
    )
    parser.add_argument(
        "--ca-bundle",
        dest="ca_bundle",
        default=None,
        help="Path to a trusted CA bundle PEM file for internal or private PKI.",
    )
    parser.add_argument(
        "--timeout",
        type=float,
        default=10.0,
        help="Request timeout in seconds. Default: 10",
    )
    parser.add_argument(
        "--header",
        action="append",
        default=[],
        metavar="NAME:VALUE",
        help="Optional header to send. Can be repeated. Avoid secrets on the command line.",
    )
    parser.add_argument(
        "--data",
        default=None,
        help="Optional request body for methods like POST or PUT. Sent as raw text.",
    )
    return parser.parse_args()


def validate_https_url(url: str) -> None:
    if not url.startswith("https://"):
        raise ValueError("URL must begin with https:// for TLS verification to apply.")


def parse_headers(header_items: list[str]) -> dict[str, str]:
    headers: dict[str, str] = {}
    for item in header_items:
        if ":" not in item:
            raise ValueError(f"Invalid header format: {item!r}. Use NAME:VALUE.")
        name, value = item.split(":", 1)
        name = name.strip()
        value = value.strip()
        if not name or not value:
            raise ValueError(f"Invalid header format: {item!r}. Use NAME:VALUE.")
        headers[name] = value
    return headers


def build_session(ca_bundle: Optional[str], headers: dict[str, str]) -> Session:
    session = requests.Session()
    session.headers.update({"Accept": "application/json"})
    if headers:
        session.headers.update(headers)

    # Keep TLS verification enabled. A custom CA bundle may be supplied for private PKI.
    if ca_bundle:
        session.verify = ca_bundle

    return session


def request_api(
    session: Session,
    method: str,
    url: str,
    timeout: float,
    data: Optional[str] = None,
) -> Response:
    method = method.upper()
    request_kwargs: dict[str, Any] = {"timeout": timeout}
    if data is not None and method in {"POST", "PUT", "PATCH", "DELETE"}:
        request_kwargs["data"] = data

    response = session.request(method, url, **request_kwargs)
    response.raise_for_status()
    return response


def print_response(response: Response) -> None:
    content_type = response.headers.get("Content-Type", "")
    if "application/json" in content_type.lower():
        try:
            parsed = response.json()
            print(json.dumps(parsed, indent=2, sort_keys=True))
            return
        except ValueError:
            pass

    print(response.text)


def main() -> int:
    args = parse_args()

    try:
        validate_https_url(args.url)
        headers = parse_headers(args.header)
        session = build_session(args.ca_bundle, headers)

        with session:
            response = request_api(
                session=session,
                method=args.method,
                url=args.url,
                timeout=args.timeout,
                data=args.data,
            )
            print_response(response)
            return 0

    except ValueError as exc:
        print(f"Input error: {exc}", file=sys.stderr)
        return 2
    except SSLError as exc:
        print(f"TLS verification failed: {exc}", file=sys.stderr)
        return 3
    except RequestException as exc:
        print(f"Request failed: {exc}", file=sys.stderr)
        return 4


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