from __future__ import annotations

from collections.abc import Mapping, Sequence
import json

import httpx
from fastapi import APIRouter, Depends, HTTPException, Request, Response, status

from ..auth import require_session
from ..models import UserSession

router = APIRouter(prefix="/teamsnap", tags=["teamsnap"])


def build_proxy_api_root(request: Request) -> str:
    scheme = request.headers.get("x-forwarded-proto", request.url.scheme)
    host = request.headers.get("x-forwarded-host", request.headers.get("host", request.url.netloc))
    return f"{scheme}://{host}/api/teamsnap"


def rewrite_teamsnap_urls(value: object, upstream_root: str, proxy_root: str) -> object:
    if isinstance(value, str):
        return value.replace(upstream_root, proxy_root)
    if isinstance(value, Mapping):
        return {key: rewrite_teamsnap_urls(item, upstream_root, proxy_root) for key, item in value.items()}
    if isinstance(value, Sequence) and not isinstance(value, (str, bytes, bytearray)):
        return [rewrite_teamsnap_urls(item, upstream_root, proxy_root) for item in value]
    return value


def build_upstream_url(request: Request, proxy_path: str) -> str:
    base = request.app.state.settings.teamsnap_api_root.rstrip("/")
    if not proxy_path:
        return base
    return f"{base}/{proxy_path.lstrip('/')}"


@router.api_route("/{proxy_path:path}", methods=["GET", "POST", "PUT", "PATCH", "DELETE"])
@router.api_route("", methods=["GET", "POST", "PUT", "PATCH", "DELETE"])
async def teamsnap_proxy(
    request: Request,
    session: UserSession = Depends(require_session),
    proxy_path: str = "",
) -> Response:
    if session.provider != "teamsnap":
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Session is not TeamSnap-backed")
    if not session.access_token:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing TeamSnap access token")

    upstream_url = build_upstream_url(request, proxy_path)
    outgoing_headers = {
        "Accept": request.headers.get("accept", "application/vnd.collection+json"),
        "Authorization": f"Bearer {session.access_token}",
    }
    if request.headers.get("content-type"):
        outgoing_headers["Content-Type"] = request.headers["content-type"]

    body = await request.body()
    async with httpx.AsyncClient(timeout=30.0) as client:
        upstream = await client.request(
            request.method,
            upstream_url,
            params=request.query_params,
            content=body or None,
            headers=outgoing_headers,
        )

    content_type = upstream.headers.get("content-type", "")
    if "json" not in content_type.lower():
        response = Response(content=upstream.content, status_code=upstream.status_code)
        if content_type:
            response.headers["Content-Type"] = content_type
        return response

    proxy_root = build_proxy_api_root(request)
    rewritten = rewrite_teamsnap_urls(upstream.json(), request.app.state.settings.teamsnap_api_root, proxy_root)
    return Response(
        content=json.dumps(rewritten),
        status_code=upstream.status_code,
        media_type=content_type or "application/json",
    )
