"""Executores separados: API interativa vs jobs pesados (OMR/envio).

O Starlette/BackgroundTasks e o ``run_in_threadpool`` compartilham o limiter
padrão do anyio. Um processamento longo ocupava esse pool e fazia board/resumo
esperarem dezenas de segundos. Jobs pesados vão para um executor dedicado.
"""
from __future__ import annotations

import logging
from concurrent.futures import ThreadPoolExecutor
from typing import Any, Callable

logger = logging.getLogger("omrcheck.concurrency")

# Poucos workers: OMR é CPU-bound; demais rotas usam o threadpool do anyio.
_HEAVY_EXECUTOR = ThreadPoolExecutor(max_workers=2, thread_name_prefix="omr-heavy")


def agendar_trabalho_pesado(func: Callable[..., Any], *args: Any, **kwargs: Any) -> None:
    """Dispara trabalho longo sem consumir o CapacityLimiter do anyio."""
    from app.tenant import clear_tenant_context, set_tenant_context, snapshot_tenant_context

    school, institute = snapshot_tenant_context()

    def _rodar() -> None:
        set_tenant_context(school, institute)
        try:
            func(*args, **kwargs)
        except Exception:
            logger.exception(
                "Falha em trabalho pesado func=%s",
                getattr(func, "__name__", repr(func)),
            )
        finally:
            clear_tenant_context()

    _HEAVY_EXECUTOR.submit(_rodar)
