# retoor <retoor@molodetz.nl>

import logging

from fastapi import APIRouter, Request, WebSocket
from starlette.responses import Response

from devplacepy.services.audit import record as audit
from devplacepy.services.containers import api, forward, store
from devplacepy.utils import not_found

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

METHODS = forward.METHODS


def _resolve(slug: str):
    instance = store.find_instance_by_ingress(slug)
    if not instance or instance.get("status") != store.ST_RUNNING:
        return None, None, None
    host, port = api.proxy_target(instance)
    return instance, host, port


@router.api_route("/{slug}", methods=METHODS)
@router.api_route("/{slug}/{path:path}", methods=METHODS)
async def proxy_http(request: Request, slug: str, path: str = ""):
    instance, host, port = _resolve(slug)
    if instance is None:
        raise not_found("No running container is published at this address")
    if not host or not port:
        return Response(
            "the published container has no reachable port", status_code=502
        )
    audit.record(
        request,
        "proxy.access",
        target_type="instance",
        target_uid=instance["uid"],
        target_label=instance.get("name"),
        metadata={"slug": slug, "path": path, "method": request.method},
        summary=f"request proxied to instance {instance.get('name')} via ingress {slug}",
        links=[audit.instance(instance["uid"], instance.get("name"))],
    )
    return await forward.proxy_http(
        request, host, port, path, prefix=f"/p/{slug}", timeout=60.0
    )


@router.websocket("/{slug}")
@router.websocket("/{slug}/{path:path}")
async def proxy_ws(websocket: WebSocket, slug: str, path: str = ""):
    instance, host, port = _resolve(slug)
    if instance is None or not host or not port:
        await websocket.close(code=1011)
        return
    audit.record(
        websocket,
        "proxy.access",
        user=None,
        target_type="instance",
        target_uid=instance["uid"],
        target_label=instance.get("name"),
        metadata={"slug": slug, "path": path, "protocol": "websocket"},
        summary=f"websocket proxied to instance {instance.get('name')} via ingress {slug}",
        links=[audit.instance(instance["uid"], instance.get("name"))],
    )
    await forward.proxy_ws(websocket, host, port, path, prefix=f"/p/{slug}")
