# Reverse proxy: backend API + раздача фронтенд-SPA (статика в образе) +
# LiveKit SFU signaling. TLS-терминация — здесь же (см. блок HTTPS ниже),
# сертификаты берутся из /etc/letsencrypt (см. docker-compose.yml, volume ro).
#
# Шаблон рендерится штатным entrypoint-скриптом официального образа nginx
# (docker-entrypoint.d/20-envsubst-on-templates.sh): при старте контейнера
# envsubst подставляет ТОЛЬКО переменные, реально заданные в окружении
# контейнера (см. `environment:` сервиса nginx в docker-compose.yml), поэтому
# нативные nginx-переменные ($scheme, $host, $http_upgrade, $remote_addr,
# $connection_upgrade и т.п.) остаются нетронутыми — с ними коллизий по
# именам нет. Результат пишется в /etc/nginx/conf.d/default.conf.
#
# ВАЖНО (stale DNS): статический `upstream { server backend:8000; }` nginx
# резолвит один раз при старте/reload и держит IP в памяти. После пересоздания
# контейнера backend (`docker compose up -d --force-recreate backend`) Docker
# выдаёт ему новый IP, а nginx продолжает стучаться по старому → 502, пока
# nginx не перезапустят. Чтобы резолвить имя заново на каждый запрос,
# используем embedded DNS Docker (127.0.0.11) через directive `resolver` и
# ПЕРЕМЕННУЮ в proxy_pass — переменные nginx не кэшируются на старте и
# резолвятся заново по истечении `valid=`.
resolver 127.0.0.11 valid=10s ipv6=off;

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

# ==========================================
# БЛОК 1: HTTP (порт 80)
# Задача: ACME-challenge для Certbot + редирект всего остального на HTTPS.
# ==========================================
server {
    listen 80;
    # Список доменов — параметр (NGINX_SERVER_NAMES в .env), не хардкод.
    server_name ${NGINX_SERVER_NAMES};

    # Раздача файлов для (авто)обновления Certbot — ОБЯЗАТЕЛЬНО оставить
    # для работы webroot-плагина.
    location ^~ /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    # Healthcheck контейнера (см. docker-compose.yml) ходит сюда напрямую по
    # HTTP — редирект ниже иначе увёл бы его на HTTPS и ломал бы wget без -L.
    location /healthz {
        return 200 "ok\n";
        add_header Content-Type text/plain;
    }

    # Жёсткий редирект всего остального на HTTPS.
    location / {
        return 301 https://$host$request_uri;
    }
}

# ==========================================
# БЛОК 2: HTTPS (порт 443)
# Задача: вся основная логика приложения — API, фронтенд, WebSocket, LiveKit.
# ==========================================
server {
    listen 443 ssl;
    server_name ${NGINX_SERVER_NAMES};

    # Путь СТАТИЧЕН (не envsubst) — реальный источник переменный:
    # /docker-entrypoint.d/15-vidconf-certs.sh (запускается раньше рендера
    # этого шаблона) копирует сюда боевой сертификат из
    # /etc/letsencrypt/live/${NGINX_CERT_NAME}, если он смонтирован с хоста
    # (см. docker-compose.yml), иначе генерирует самоподписанный — это
    # позволяет `docker compose up` стартовать локально (dev) БЕЗ реальных
    # сертификатов Let's Encrypt (см. docs/deploy/dev-setup.md).
    ssl_certificate /etc/nginx/certs/fullchain.pem;
    ssl_certificate_key /etc/nginx/certs/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    # --- Backend API ---
    # Проброс через переменную: proxy_pass с переменной НЕ выполняет
    # автоматическую подстановку URI (в отличие от статического
    # `proxy_pass http://upstream/prefix/;`), поэтому URI-часть в proxy_pass
    # не указываем — nginx передаёт исходный URI запроса как есть (path +
    # query), что и сохраняет прежний маппинг /api/ -> backend:8000/api/
    # (префикс совпадает 1-в-1, подмены не требовалось и раньше).
    # Upgrade-заголовки нужны и обычным HTTP-запросам (без `Upgrade` в запросе
    # `map $http_upgrade $connection_upgrade` выше подставляет `close`, что не
    # ломает keep-alive обычных ответов), и WS-эндпоинту чата конференции
    # (`WS /api/v1/conferences/{id}/chat`) — он живёт под тем же
    # префиксом /api/, а не под отдельным /ws/.
    location /api/ {
        set $backend_upstream http://backend:8000;
        proxy_pass $backend_upstream;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # $scheme здесь равен 'https' — критично, чтобы бэкенд (FastAPI)
        # генерировал корректные абсолютные ссылки и принимал Secure-куки.
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 3600s;
    }

    # --- WebSocket upgrade для чата ---
    location /ws/ {
        set $backend_upstream http://backend:8000;
        proxy_pass $backend_upstream;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $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_read_timeout 3600s;
    }

    # --- LiveKit SFU signaling (WebSocket) ---
    # Доступен только когда стек запущен с профилем `media`
    # (см. docker-compose.yml) — без него resolver вернёт NXDOMAIN на первый
    # запрос к этому location, что ожидаемо.
    # Здесь префикс /livekit/ нужно СНЯТЬ (как раньше делал
    # `proxy_pass http://livekit_upstream/;`). С переменной в proxy_pass
    # автоматическая подмена недоступна, поэтому переписываем URI явно через
    # rewrite ... break — nginx передаст на upstream уже переписанный $uri.
    # ВАЖНО: `set` должен идти ДО `rewrite ... break` — break прерывает
    # выполнение всех последующих директив модуля rewrite (включая set) в
    # этом location, иначе переменная останется неинициализированной.
    location /livekit/ {
        set $livekit_upstream http://livekit:7880;
        rewrite ^/livekit/(.*)$ /$1 break;
        proxy_pass $livekit_upstream;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $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_read_timeout 3600s;
    }

    # --- Метрики backend: `GET /metrics` без авторизации
    # внутри приложения (backend/api/metrics.py) — снаружи периметра нарочно
    # закрываем явным запретом. Это ОБЯЗАТЕЛЬНО именно exact-match
    # (`location = /metrics`): ниже есть catch-all `location /` (раздача
    # фронтенд-SPA), который иначе отдал бы на /metrics файл фронта (или
    # index.html через try_files). Exact-match в nginx приоритетнее любого
    # prefix-location, поэтому 403 срабатывает раньше SPA-раздачи.
    # Prometheus (профиль compose `monitoring`) ходит в backend НАПРЯМУЮ по
    # внутренней docker-сети (`backend:8000/metrics`), минуя nginx.
    location = /metrics {
        return 403;
    }

    # --- Схема OpenAPI: FastAPI отдаёт её на КОРНЕВОМ пути /openapi.json (не
    # под /api/ — маршруты backend объявлены с явным префиксом /api/... в
    # декораторах, а не через APIRouter(prefix=...), см. backend/main.py),
    # поэтому без этого location запрос попадал бы в SPA-фолбэк ниже
    # (`location /` отдаёт index.html фронта вместо схемы — мешало отладке).
    location = /openapi.json {
        set $backend_upstream http://backend:8000;
        proxy_pass $backend_upstream;
        proxy_set_header Host $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;
    }

    # --- Медиа (аватары): раздача напрямую из volume, в обход backend. ---
    location /media/ {
        alias /media/;
        autoindex off;
    }

    # --- Frontend SPA (React + Vite): статика вкомпилирована в образ nginx
    # (frontend/Dockerfile) в /usr/share/nginx/html. `try_files` с
    # history-fallback на /index.html нужен для клиентского роутинга
    # react-router (deep-ссылки вида /conferences/<id>, /admin/settings —
    # при перезагрузке страницы отдаётся index.html, дальше роутит SPA).
    # Более специфичные location выше (/api/, /media/, = /metrics, /livekit/,
    # /ws/) матчатся раньше этого catch-all, поэтому API и метрики не
    # перехватываются фронтом.
    location / {
        root /usr/share/nginx/html;
        try_files $uri $uri/ /index.html;
    }
}
