import re
from collections.abc import Generator

from fastapi import HTTPException, Request
from sqlalchemy.orm import Session

from custos_precificacao import planejamento_schema
from custos_precificacao.db import SessionLocal, engine

CABECALHO_PLANEJAMENTO = "X-Planejamento"
_ROTA_DE_PLANEJAMENTO = re.compile(r"^/planejamentos/([^/]+)/")


def rotear_para_planejamento(session: Session, codigo: str | None) -> str | None:
    """Aponta a sessão para o schema do Planejamento pedido (ou do padrão: o oficial, senão o mais recente).
    Devolve o código escolhido; None quando não há roteamento (SQLite, ou banco sem Planejamento com schema)."""
    if not planejamento_schema.e_postgres(engine):
        return None
    linha = planejamento_schema.planejamento_por_codigo(engine, codigo) if codigo else planejamento_schema.planejamento_padrao(engine)
    if codigo and linha is None:
        raise HTTPException(status_code=404, detail=f"Planejamento {codigo!r} não encontrado")
    if linha is None:
        return None
    if not linha.schema:
        raise HTTPException(status_code=409, detail=f"Planejamento {linha.codigo!r} ainda não tem os dados separados (rode a inicialização)")
    planejamento_schema.apontar(session, linha.schema)
    session.info["planejamento_codigo"] = linha.codigo
    return linha.codigo


def get_session(request: Request) -> Generator[Session, None, None]:
    session = SessionLocal()
    try:
        escolhido = rotear_para_planejamento(session, request.headers.get(CABECALHO_PLANEJAMENTO))
        da_rota = _ROTA_DE_PLANEJAMENTO.match(request.url.path)
        if escolhido and da_rota and da_rota.group(1) != escolhido:
            raise HTTPException(
                status_code=409,
                detail=f"O Planejamento {da_rota.group(1)!r} da rota não é o selecionado ({escolhido!r})",
            )
        yield session
    finally:
        session.close()
