"""Os resultados da precificação por Centro de Resultados no formato das telas de Premissas e das Fotos (versões congeladas)."""

from decimal import Decimal

from sqlalchemy.orm import Session

from custos_precificacao import precificacao_centros as pc, precificacao_primaria as pp
from custos_precificacao.api.schemas import (
    CentroVersaoOut,
    ConsolidadaVersaoOut,
    LinhaDreVersaoOut,
    ProdutoVersaoOut,
    ResultadoVersaoOut,
)


def calcular(session: Session) -> tuple[pc.ResultadoCentros, pc.DreConsolidada]:
    """A precificação dos Centros e a DRE Consolidada. ValueError se não der (sem Meta de Lucro, sem custeio, percentuais ≥ 100%…)."""
    resultado = pc.calcular_centros(session)
    if not any(c.linhas for c in resultado.centros.values()):
        avisos = [c.aviso for c in resultado.centros.values() if c.aviso]
        raise ValueError(avisos[0] if avisos else "Nenhum produto precificado: calcule os custos e defina a Meta de Lucro")
    return resultado, pc.dre_consolidada(session, resultado)


def resultado_out(r: pp.Resultado) -> ResultadoVersaoOut:
    return ResultadoVersaoOut(
        preco=r.preco, impostos=r.impostos, custo=r.custo, despesas_variaveis=r.despesas_variaveis, margem_contribuicao=r.margem_contribuicao,
        despesas_fixas=r.despesas_fixas, resultado_operacional=r.resultado_operacional, destinacao=r.destinacao, resultado_final=r.resultado_final,
    )


def total_consolidado(resultado: pc.ResultadoCentros) -> pp.Resultado:
    total = pp.Resultado(*([Decimal(0)] * 9))
    for centro in resultado.centros.values():
        total = total.somar(centro.total_geral())
    return total


def centros_out(resultado: pc.ResultadoCentros, dre: pc.DreConsolidada) -> list[CentroVersaoOut]:
    por_codigo = {r.codigo: r for r in dre.reconciliacao}
    saida = []
    for codigo, centro in resultado.centros.items():
        rec = por_codigo.get(codigo)
        saida.append(CentroVersaoOut(
            codigo=codigo, nome=resultado.cenarios[codigo].nome, a_alocar=resultado.cenarios[codigo].a_alocar,
            quantidade=sum((l.quantidade for l in centro.linhas), Decimal(0)),
            despesas_adicionais=rec.despesas_adicionais if rec else Decimal(0), efeito=rec.efeito if rec else Decimal(0),
            total=resultado_out(centro.total_geral()),
        ))
    return saida


def produtos_out(resultado: pc.ResultadoCentros) -> list[ProdutoVersaoOut]:
    saida = []
    for codigo, centro in resultado.centros.items():
        for l in centro.linhas:
            saida.append(ProdutoVersaoOut(
                centro_codigo=codigo, centro_nome=resultado.cenarios[codigo].nome, produto_codigo=l.produto.codigo, produto_nome=l.produto.nome,
                quantidade=l.quantidade, preco_tabela=l.preco_definido, preco_liquido=l.ao_definido.preco, custo_unitario=l.ao_definido.custo,
                resultado_operacional_unitario=l.ao_definido.resultado_operacional,
            ))
    return saida


def consolidada_out(resultado: pc.ResultadoCentros, dre: pc.DreConsolidada) -> ConsolidadaVersaoOut:
    def linhas(origem):
        return [
            LinhaDreVersaoOut(rotulo=l.rotulo, valor=l.valor, nivel=l.nivel, estilo=l.estilo, codigo=l.codigo, desembolso=l.desembolso, retencao=l.retencao)
            for l in origem
        ]

    return ConsolidadaVersaoOut(
        total=resultado_out(total_consolidado(resultado)), resultado_primaria=dre.resultado_primaria, dre=linhas(dre.linhas),
        informativos=linhas(dre.informativos),
    )
