# retoor <retoor@molodetz.nl>

import logging

import httpx
from fastapi import APIRouter, Request
from starlette.requests import ClientDisconnect
from starlette.responses import PlainTextResponse, Response

from devplacepy.config import XMLRPC_BIND, XMLRPC_PORT

logger = logging.getLogger(__name__)
router = APIRouter()

CONNECT_HOST = XMLRPC_BIND if XMLRPC_BIND not in ("0.0.0.0", "::") else "127.0.0.1"
TARGET_URL = f"http://{CONNECT_HOST}:{XMLRPC_PORT}/"
TIMEOUT_SECONDS = 65.0
FORWARD_HEADERS = (
    "authorization",
    "x-api-key",
    "x-real-ip",
    "x-forwarded-for",
    "content-type",
)

USAGE = (
    "DevPlace XML-RPC bridge\n\n"
    "POST XML-RPC method calls to this endpoint. Every documented REST endpoint is\n"
    "exposed as a method named after its id with dots (for example posts.create,\n"
    "feed.index, profile.update). Each method takes ONE struct of named parameters;\n"
    "authenticate with 'api_key' inside the struct or an X-API-KEY / Bearer header.\n\n"
    "Introspection: system.listMethods, system.methodHelp, system.methodSignature.\n"
    "Batching: system.multicall.\n\n"
    "Python example:\n"
    "  import xmlrpc.client\n"
    "  proxy = xmlrpc.client.ServerProxy('https://your-host/xmlrpc', allow_none=True)\n"
    "  print(proxy.system.listMethods())\n"
    "  proxy.posts.create({'title': 'Hi', 'body': '...', 'api_key': 'YOUR_KEY'})\n"
)


@router.get("")
@router.get("/")
@router.get("/{path:path}")
async def info(request: Request, path: str = "") -> PlainTextResponse:
    return PlainTextResponse(USAGE)


@router.post("")
@router.post("/")
@router.post("/{path:path}")
async def proxy(request: Request, path: str = "") -> Response:
    try:
        body = await request.body()
    except ClientDisconnect:
        logger.warning("XML-RPC client disconnected before request body was read")
        return PlainTextResponse("Client disconnected", status_code=400)
    headers = {
        key: value
        for key, value in request.headers.items()
        if key.lower() in FORWARD_HEADERS
    }
    headers.setdefault("content-type", "text/xml")
    try:
        async with httpx.AsyncClient(timeout=TIMEOUT_SECONDS) as client:
            upstream = await client.post(TARGET_URL, content=body, headers=headers)
    except httpx.HTTPError as exc:
        logger.warning("XML-RPC bridge unavailable: %s", exc)
        return PlainTextResponse(
            "XML-RPC bridge is not available.", status_code=502
        )
    return Response(
        content=upstream.content,
        status_code=upstream.status_code,
        media_type=upstream.headers.get("content-type", "text/xml"),
    )
