map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}
    
map $http_origin $cors_origin {
    # AppFlowy Web origin
    "~^http://localhost:3000$" $http_origin;
    default "null";
}

server {
    listen 8086;
    client_max_body_size 10M;

    underscores_in_headers on;
    set $appflowy_cloud_backend "http://192.168.3.3:8000";
    set $gotrue_backend "http://192.168.3.3:9999";
    set $admin_frontend_backend "http://192.168.3.3:3001";
    set $appflowy_web_backend "http://192.168.3.3:8090";
    set $appflowy_ai_backend "http://192.168.3.3:5001";
    set $minio_backend "http://192.168.3.3:9001";
    set $minio_api_backend "http://192.168.3.3:9000";
    # Host name for minio, used internally within docker compose
    set $minio_internal_host "192.168.3.3:9000";
    set $portainer_backend "http://192.168.3.3:9000";
    set $pgadmin_backend "http://192.168.3.3:80";

    # GoTrue
    location /gotrue/ {
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin' $cors_origin always;
            add_header 'Access-Control-Allow-Credentials' 'true' always;
            add_header 'Access-Control-Allow-Headers' '*' always;
            add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, PATCH, OPTIONS' always;
            add_header 'Access-Control-Max-Age' 3600 always;
            add_header 'Content-Type' 'text/plain charset=UTF-8' always;
            add_header 'Content-Length' 0 always;
            return 204;
        }

        proxy_pass $gotrue_backend;

        rewrite ^/gotrue(/.*)$ $1 break;

        # Allow headers like redirect_to to be handed over to the gotrue
        # for correct redirecting
        proxy_set_header Host $http_host;
        proxy_pass_request_headers on;
    }

    # WebSocket
    location /ws {
        proxy_pass $appflowy_cloud_backend;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
        proxy_read_timeout 86400;
    }

    location /api {
        proxy_pass $appflowy_cloud_backend;
        proxy_set_header X-Request-Id $request_id;
        proxy_set_header Host $http_host;

        # Set CORS headers for other requests
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin' $cors_origin always;
            add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, PATCH, OPTIONS' always;
            add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, Accept, Client-Version, Device-Id' always;
            add_header 'Access-Control-Max-Age' 3600 always;
            return 204;
        }

        add_header 'Access-Control-Allow-Origin' $cors_origin always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, PATCH, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, Accept, Client-Version, Device-Id' always;
        add_header 'Access-Control-Max-Age' 3600 always;

        location ~* ^/api/workspace/([a-zA-Z0-9_-]+)/publish$ {
            proxy_pass $appflowy_cloud_backend;
            proxy_request_buffering off;
            client_max_body_size 256M;
            if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Allow-Origin' $cors_origin always;
                add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, PATCH, OPTIONS' always;
                add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, Accept, Client-Version, Device-Id' always;
                add_header 'Access-Control-Max-Age' 3600 always;
                return 204;
            }

            add_header 'Access-Control-Allow-Origin' $cors_origin always;
            add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, PATCH, OPTIONS' always;
            add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, Accept, Client-Version, Device-Id' always;
            add_header 'Access-Control-Max-Age' 3600 always;
        }

        # AppFlowy-Cloud
        location /api/chat {
            proxy_pass $appflowy_cloud_backend;

            proxy_http_version 1.1;
            proxy_set_header Connection "";
            chunked_transfer_encoding on;
            proxy_buffering off;
            proxy_cache off;

            proxy_read_timeout 600s;
            proxy_connect_timeout 600s;
            proxy_send_timeout 600s;
        }

        location /api/import {
            proxy_pass $appflowy_cloud_backend;

            # Set headers
            proxy_set_header X-Request-Id $request_id;
            proxy_set_header Host $http_host;

            # Handle CORS
            add_header 'Access-Control-Allow-Origin' $cors_origin always;
            add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, PATCH, OPTIONS' always;
            add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, Accept, Device-Id' always;
            add_header 'Access-Control-Max-Age' 3600 always;

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

            # Disable buffering for large file uploads
            proxy_request_buffering off;
            proxy_buffering off;
            proxy_cache off;
            client_max_body_size 2G;
        }
    }


    # AppFlowy AI
    location /ai {
        proxy_pass $appflowy_ai_backend;
        proxy_set_header Host $host;
        proxy_pass_request_headers on;
    }

    # Minio Web UI
    # Derive from: https://min.io/docs/minio/linux/integrations/setup-nginx-proxy-with-minio.html
    # Optional Module, comment this section if you are did not deploy minio in docker-compose.yml
    # This endpoint is meant to be used for the MinIO Web UI, accessible via the admin portal
    location /minio/ {
        proxy_pass $minio_backend;

        rewrite ^/minio/(.*) /$1 break;
        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 X-NginX-Proxy true;

        ## This is necessary to pass the correct IP to be hashed
        real_ip_header X-Real-IP;

        proxy_connect_timeout 300;

        ## To support websockets in MinIO versions released after January 2023
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        # Some environments may encounter CORS errors (Kubernetes + Nginx Ingress)
        # Uncomment the following line to set the Origin request to an empty string
        # proxy_set_header Origin '';

        chunked_transfer_encoding off;
    }

    # Optional Module, comment this section if you are did not deploy minio in docker-compose.yml
    # This is used for presigned url, which is needs to be exposed to the AppFlowy client application.
    location /minio-api/ {
        proxy_pass $minio_api_backend;

        # Set the host to internal host because the presigned url was signed against the internal host
        proxy_set_header Host $minio_internal_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;

        rewrite ^/minio-api/(.*) /$1 break;

        proxy_connect_timeout 300;
        # Default is HTTP/1, keepalive is only enabled in HTTP/1.1
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        chunked_transfer_encoding off;
    }

    # PgAdmin
    # Optional Module, comment this section if you are did not deploy pgadmin in docker-compose.yml
    location /pgadmin/ {
        set $pgadmin pgadmin;
        proxy_pass $pgadmin_backend;

        proxy_set_header X-Script-Name /pgadmin;
        proxy_set_header X-Scheme $scheme;
        proxy_set_header Host $host;
        proxy_redirect off;
    }

    # Portainer
    # Optional Module, comment this section if you are did not deploy portainer in docker-compose.yml
    location /portainer/ {
        proxy_pass $portainer_backend;
        rewrite ^/portainer/(.*) /$1 break;
    }

    # Admin Frontend
    # Optional Module, comment this section if you are did not deploy admin_frontend in docker-compose.yml
    location /console {
        proxy_pass $admin_frontend_backend;

        proxy_set_header X-Scheme $scheme;
        proxy_set_header Host $host;
    }

    # AppFlowy Web
    location / {
        proxy_pass $appflowy_web_backend;
        proxy_set_header X-Scheme $scheme;
        proxy_set_header Host $host;
    }
}