# AUTOGENERATED FILE
from fastapi import FastAPI, Request, HTTPException, Header, Depends
from fastapi.responses import FileResponse, JSONResponse
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from fastapi.staticfiles import StaticFiles
from starlette.responses import Response
from starlette.testclient import TestClient
from starlette.exceptions import HTTPException as StarletteHTTPException
from pathlib import Path
import json
import re
from pydantic import BaseModel
from fastapi.middleware.cors import CORSMiddleware
from os import path as file_path

from naeural_core.utils.uvicorn_fast_api_ipc_manager import UvicornPluginComms

eng = UvicornPluginComms(port={{ manager_port }}, auth={{ manager_auth }})

app = FastAPI(
  title={{ api_title }},
  summary={{ api_summary }},
  description={{ api_description }},
  version={{ api_version }},
)

app.add_middleware(
  CORSMiddleware,
  allow_origins=["*"],
  allow_credentials=True,
  allow_methods=["*"],
  allow_headers=["*"],
)

STATIC_DIR = "{{ static_directory }}"
DEBUG = {{ debug_web_app }}
{% if default_route is not none %}
DEFAULT_ROUTE = "{{ default_route }}"
{% else %}
DEFAULT_ROUTE = None
{% endif %}

# Define security scheme for Swagger UI
security = HTTPBearer()

def get_bearer_token(credentials: HTTPAuthorizationCredentials = Depends(security)) -> str:
    """
    Extract the Bearer token using FastAPI's HTTPBearer dependency.

    Parameters
    ----------
    credentials : HTTPAuthorizationCredentials
        Automatically provided by FastAPI when using HTTPBearer.

    Returns
    -------
    str
        The extracted token.

    Raises
    ------
    HTTPException
        If the token is invalid or missing.
    """
    if DEBUG:
        print(f"Received authorization credentials: {credentials}")
    if not credentials:
        raise HTTPException(status_code=401, detail="Authorization credentials are missing. Please provide a Bearer token.")
    if credentials.scheme.lower() != "bearer":
        raise HTTPException(status_code=401, detail=f"Invalid authorization scheme '{credentials.scheme}'. Expected 'Bearer'.")
    return credentials.credentials



{% for item in node_comm_params %}
{% if item['method']=='post' %}
class {{ item['name'] }}Model(BaseModel):
  {% if item['args'] %}
  {% for arg in item['args'] %}
  {{ arg }}
  {% endfor %}
  {% else %}
  pass
  {% endif %}


@app.post("/{{ item['name'] }}")
async def {{ item['name'] }}(
  request: {{ item['name'] }}Model
  {% if item['require_token'] %}, token: str = Depends(get_bearer_token){% endif %}
):
  """{{ item['endpoint_doc'] }}"""
  {% for param in item['params'] %}
  {{ param }} = request.{{ param }}
  {% endfor %}

  {% if item['require_token'] %}
  result = await eng.call_plugin("{{ item['name'] }}", token{% for param in item['params'] %}, {{ param }}{% endfor %})
  if result.get("result") == "Unauthorized token" or result.get("status_code") == 401:
    raise HTTPException(status_code=401, detail=result.get("result", result))  
  {% else %}
  result = await eng.call_plugin("{{ item['name'] }}"{% for param in item['params'] %}, {{ param }}{% endfor %})
  {% endif %}
  return result

{% else %}

{% if item['method'] is not none %}@app.{{ item['method'] }}("/{{ item['name'] }}"){% endif %}
async def {{ item['name'] }}(
  {% for arg in item['args'] %}{{ arg }}, {% if not loop.last %} {% endif %}{% endfor %}
  {% if item['require_token'] %}token: str = Depends(get_bearer_token){% endif %}
):
  """{{ item['endpoint_doc'] }}"""
  {% if item['require_token'] %}
  result = await eng.call_plugin("{{ item['name'] }}", token{% for param in item['params'] %}, {{ param }}{% endfor %})
  if result.get("result") == "Unauthorized token" or result.get("status_code") == 401:
    raise HTTPException(status_code=401, detail=result.get("result", result))  
  {% else %}
  result = await eng.call_plugin("{{ item['name'] }}"{% for param in item['params'] %}, {{ param }}{% endfor %})
  {% endif %}
  return result

{% endif %}
{% endfor %}


{% for item in html_files %}
@app.{{ item['method'] }}('{{ item['route'] }}')
async def html_route{{ loop.index }}():
  return FileResponse(file_path.join(STATIC_DIR, '{{ item['name'] }}'))

{% endfor %}


@app.exception_handler(StarletteHTTPException)
async def custom_404_handler(request: Request, exc: StarletteHTTPException):
    if exc.status_code == 404:
        # Regex pattern to match files with specific extensions
        pattern = re.compile(r".*\.(js|png|jpg|css|jpeg|gif|svg|ico)$")
        if pattern.match(request.url.path):
            file_path = Path(STATIC_DIR) / request.url.path.strip("/")
            if file_path.exists() and file_path.is_file():
                return FileResponse(file_path)

    if DEFAULT_ROUTE is not None and request.url.path != DEFAULT_ROUTE:
        # Using TestClient to simulate a request internally
        with TestClient(app) as client:
            # Make a get request to the default route
            response = client.get(DEFAULT_ROUTE)
            return Response(content=response.content, status_code=response.status_code, headers=dict(response.headers))
    # endif DEFAULT_ROUTE defined

    print(f"StarletteHTTPException during request for {request.url}:\n{exc}")
    return JSONResponse(
        status_code=exc.status_code,
        content={"detail": exc.detail or "An error occurred."},
    )

app.mount(f"/{STATIC_DIR}", StaticFiles(directory=STATIC_DIR), name="static")
