from dataclasses import dataclass
from decimal import Decimal

from sqlalchemy.orm import Session

from custos_precificacao.explosao import rendimento_atual, volume_de_producao
from custos_precificacao.models import (
    Ambiente,
    GrupoMaoDeObra,
    Maquina,
    Produto,
    RoteiroAmbiente,
    RoteiroMaoDeObra,
    RoteiroMaquina,
)

# tipo -> (modelo do recurso, modelo do roteiro, coluna FK no roteiro)
RECURSOS_CAPACIDADE: dict[str, tuple[type, type, str]] = {
    "funcionarios": (GrupoMaoDeObra, RoteiroMaoDeObra, "grupo_id"),  # a capacidade da mão de obra é a do grupo Depto-Cargo
    "maquinas": (Maquina, RoteiroMaquina, "maquina_id"),
    "ambientes": (Ambiente, RoteiroAmbiente, "ambiente_id"),
}


@dataclass
class Capacidade:
    horas_uteis_mensais: Decimal
    horas_consumidas_mensais: Decimal
    horas_ociosas: Decimal  # negativo = sobrecarga
    utilizacao_pct: Decimal
    custo_ociosidade: Decimal


def _lotes_por_mes(session: Session, produto: Produto) -> Decimal | None:
    rendimento = rendimento_atual(produto)  # com bacia, o rendimento real (antes só valia o rendimento cadastrado)
    volume = volume_de_producao(session, produto)  # informado + o que os acabados pedem deste intermediário
    if not rendimento or not volume:
        return None
    return volume / rendimento


def calcular_capacidade(session: Session, tipo: str, recurso) -> Capacidade:
    """Ocupação mensal de um recurso (Funcionário/Máquina/Ambiente) a partir do roteiro.

    `tempo_horas` é por lote (mesma convenção do custeio), então
    horas consumidas = Σ tempo_horas × (volume de produção ÷ rendimento) por produto (volume = informado + calculado pela estrutura).
    Produtos sem volume estimado ou sem rendimento são ignorados (não é erro). Independe de
    Cenário: desligar um recurso do rateio muda o custo rateado, não a ocupação física.
    """
    _, modelo_roteiro, campo_fk = RECURSOS_CAPACIDADE[tipo]
    linhas = session.query(modelo_roteiro).filter(getattr(modelo_roteiro, campo_fk) == recurso.id)

    consumidas = Decimal(0)
    for linha in linhas:
        lotes = _lotes_por_mes(session, linha.produto)
        if lotes is None:
            continue
        consumidas += linha.tempo_horas * lotes

    uteis = recurso.horas_uteis_mensais
    ociosas = uteis - consumidas
    utilizacao = consumidas / uteis if uteis else Decimal(0)
    custo_ociosidade = max(ociosas, Decimal(0)) * recurso.custo_hora
    return Capacidade(uteis, consumidas, ociosas, utilizacao, custo_ociosidade)
