"""despesa fixa e variável (sem competência) e o critério 'custo primário' nos direcionadores

Revision ID: b1d3f5a7c9e2
Revises: a9c1e3f5b7d9
Create Date: 2026-11-01 10:00:00.000000

A Despesa passa a ser um cadastro do Planejamento (sem competência mensal): `titulo`, `tipo` (fixa | variável), `percentual_receita` (variável) e o
`valor` mensal (fixa); `direcionador_id` fica opcional (só a fixa é rateada). As despesas já cadastradas viram fixas (título = descrição ou código) e
só ficam as da competência mais recente (as demais já tinham sido apuradas). O `direcionador.base` ganha 'custo_primario'. Só roda nos schemas de
Planejamento (ver f1a9c3d7e284).
"""
from typing import Sequence, Union

import sqlalchemy as sa
from alembic import op


# revision identifiers, used by Alembic.
revision: str = 'b1d3f5a7c9e2'
down_revision: Union[str, None] = 'a9c1e3f5b7d9'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def _no_schema_comum() -> bool:
    contexto = op.get_context()
    return contexto.dialect.name == 'postgresql' and contexto.version_table_schema is None


def upgrade() -> None:
    if _no_schema_comum():
        return
    liga = op.get_bind()
    op.add_column('despesa', sa.Column('titulo', sa.String(200), nullable=True))
    op.add_column('despesa', sa.Column('tipo', sa.String(10), nullable=False, server_default='fixa'))
    op.add_column('despesa', sa.Column('percentual_receita', sa.Numeric(8, 6), nullable=True))
    liga.execute(sa.text("update despesa set titulo = coalesce(nullif(trim(descricao), ''), codigo)"))
    # só a competência mais recente continua valendo
    liga.execute(sa.text("delete from despesa where competencia < (select max(competencia) from despesa)"))
    liga.execute(sa.text("delete from classificacao_credito where origem = 'despesa' and origem_id not in (select id from despesa)"))
    with op.batch_alter_table('despesa') as lote:
        lote.alter_column('titulo', existing_type=sa.String(200), nullable=False)
        lote.alter_column('direcionador_id', existing_type=sa.Integer(), nullable=True)
        lote.drop_column('competencia')
        lote.create_check_constraint('ck_despesa_tipo', "tipo in ('fixa', 'variavel')")
    with op.batch_alter_table('direcionador') as lote:
        lote.drop_constraint('ck_direcionador_base', type_='check')
        lote.create_check_constraint('ck_direcionador_base', "base in ('tempo', 'quantidade_produzida', 'custo_primario')")


def downgrade() -> None:
    if _no_schema_comum():
        return
    liga = op.get_bind()
    # variáveis não existiam: saem; o que sobra volta a ter direcionador obrigatório (as sem direcionador também saem)
    liga.execute(sa.text("delete from classificacao_credito where origem = 'despesa' and origem_id in (select id from despesa where tipo = 'variavel' or direcionador_id is null)"))
    liga.execute(sa.text("delete from despesa where tipo = 'variavel' or direcionador_id is null"))
    liga.execute(sa.text("update direcionador set base = 'quantidade_produzida' where base = 'custo_primario'"))
    with op.batch_alter_table('direcionador') as lote:
        lote.drop_constraint('ck_direcionador_base', type_='check')
        lote.create_check_constraint('ck_direcionador_base', "base in ('tempo', 'quantidade_produzida')")
    op.add_column('despesa', sa.Column('competencia', sa.Date(), nullable=True))
    liga.execute(sa.text("update despesa set competencia = date_trunc('month', current_date)") if liga.dialect.name == 'postgresql'
                 else sa.text("update despesa set competencia = date('now', 'start of month')"))
    with op.batch_alter_table('despesa') as lote:
        lote.alter_column('competencia', existing_type=sa.Date(), nullable=False)
        lote.alter_column('direcionador_id', existing_type=sa.Integer(), nullable=False)
        lote.drop_constraint('ck_despesa_tipo', type_='check')
        lote.drop_column('percentual_receita')
        lote.drop_column('tipo')
        lote.drop_column('titulo')
