# Global error_log (main context). Without this, nginx opens its compiled-in
# default (/var/log/nginx/error.log) at startup before reaching the http-block
# error_log, which fails with permission denied when run as a non-root user.
error_log logs/nginx-error.log warn;
events {
    worker_connections 1024;
}
pid logs/nginx.pid;
http {
    # Basic settings
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    # Logging
    access_log logs/nginx-access.log;
    error_log logs/nginx-error.log;

    # Upstream servers (using 127.0.0.1 for local development)
    upstream gateway {
        server 127.0.0.1:8001;
    }

    upstream frontend {
        server 127.0.0.1:3000;
    }

    server {
        listen 2026;
        listen [::]:2026;
        server_name _;

        # Keep the unified nginx endpoint same-origin by default. When split
        # frontend/backend or port-forwarded deployments need browser CORS,
        # configure the Gateway allowlist with GATEWAY_CORS_ORIGINS so CORS and
        # CSRF origin checks stay aligned instead of approving every origin at
        # the proxy layer.

        # LangGraph-compatible API routes served by Gateway.
        # Rewrites /api/langgraph/* to /api/* before proxying to Gateway.
        location /api/langgraph/ {
            rewrite ^/api/langgraph/(.*) /api/$1 break;
            proxy_pass http://gateway;
            proxy_http_version 1.1;

            # Headers
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header Connection '';

            # SSE/Streaming support
            proxy_buffering off;
            proxy_cache off;
            proxy_set_header X-Accel-Buffering no;

            # Timeouts for long-running requests
            proxy_connect_timeout 600s;
            proxy_send_timeout 600s;
            proxy_read_timeout 600s;

            # Chunked transfer encoding
            chunked_transfer_encoding on;
        }

        # Custom API: Models endpoint
        location /api/models {
            proxy_pass http://gateway;
            proxy_http_version 1.1;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            # Disable buffering to avoid permission errors when nginx
            # runs as a non-root user (e.g. local development).
            proxy_buffering off;
            proxy_cache off;
        }

        # Custom API: Memory endpoint
        location /api/memory {
            proxy_pass http://gateway;
            proxy_http_version 1.1;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_buffering off;
            proxy_cache off;
        }

        # Custom API: MCP configuration endpoint
        location /api/mcp {
            proxy_pass http://gateway;
            proxy_http_version 1.1;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_buffering off;
            proxy_cache off;
        }

        # Custom API: Skills configuration endpoint
        location /api/skills {
            proxy_pass http://gateway;
            proxy_http_version 1.1;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_buffering off;
            proxy_cache off;
        }

        # Custom API: Agents endpoint
        location /api/agents {
            proxy_pass http://gateway;
            proxy_http_version 1.1;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_buffering off;
            proxy_cache off;
        }

        # Custom API: Uploads endpoint
        location ~ ^/api/threads/[^/]+/uploads {
            proxy_pass http://gateway;
            proxy_http_version 1.1;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            # Large file upload support
            client_max_body_size 100M;
            proxy_request_buffering off;

            # Disable response buffering to avoid permission errors
            proxy_buffering off;
            proxy_cache off;
        }

        # Custom API: Other endpoints under /api/threads
        location ~ ^/api/threads {
            proxy_pass http://gateway;
            proxy_http_version 1.1;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_buffering off;
            proxy_cache off;
        }

        # API Documentation: Swagger UI
        location /api/docs {
            proxy_pass http://gateway/docs  ;
            proxy_http_version 1.1;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_buffering off;
            proxy_cache off;
        }

        # API Documentation: ReDoc
        location /api/redoc {
            proxy_pass http://gateway/redoc;
            proxy_http_version 1.1;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_buffering off;
            proxy_cache off;
        }

        # API Documentation: OpenAPI Schema
        location /openapi.json {
            proxy_pass http://gateway;
            proxy_http_version 1.1;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_buffering off;
            proxy_cache off;
        }

        # Health check endpoint (gateway)
        location /health {
            proxy_pass http://gateway;
            proxy_http_version 1.1;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_buffering off;
            proxy_cache off;
        }

        # Catch-all for any /api/* prefix not matched by a more specific block above.
        # Covers the auth module (/api/v1/auth/login, /me, /change-password, ...),
        # plus feedback / runs / token-usage routes that 2.0-rc added without
        # updating this nginx config. Longest-prefix matching ensures the explicit
        # blocks above (/api/models, /api/threads regex, /api/langgraph/, ...) still
        # win for their paths — only truly unmatched /api/* requests land here.
        location /api/ {
            proxy_pass http://gateway;
            proxy_http_version 1.1;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            # Auth endpoints set HttpOnly cookies — make sure nginx doesn't
            # strip the Set-Cookie header from upstream responses.
            proxy_pass_header Set-Cookie;

            # Disable buffering to avoid permission errors when nginx
            # runs as a non-root user (e.g. local development).
            proxy_buffering off;
            proxy_cache off;
        }

        # All other requests go to frontend
        location / {
            proxy_pass http://frontend;
            proxy_http_version 1.1;

            # Headers
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_cache_bypass $http_upgrade;

            # Disable response buffering for the frontend. Without this,
            # nginx tries to spool large upstream responses (e.g. Next.js
            # static chunks) into ``proxy_temp_path``, which defaults to
            # the system-owned ``/var/lib/nginx/proxy`` and fails with
            # ``[crit] open() ... failed (13: Permission denied)`` when
            # nginx is launched as a non-root user (every dev machine
            # except production root containers). The symptom on the
            # client side is ``ERR_INCOMPLETE_CHUNKED_ENCODING`` and
            # ``ChunkLoadError`` partway through page hydration.
            #
            # Streaming the response straight through avoids the
            # temp-file path entirely. The frontend already sets its
            # own cache headers, so we don't lose anything from
            # disabling nginx-side buffering.
            proxy_buffering off;
            proxy_request_buffering off;

            # Timeouts
            proxy_connect_timeout 600s;
            proxy_send_timeout 600s;
            proxy_read_timeout 600s;
        }
    }
}
