"""gasto itemizado (desembolso/retencao) em funcionario/maquina/ambiente

Revision ID: c2c76b5719eb
Revises: fad2e725683e
Create Date: 2026-09-17 20:30:00.000000

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


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


def upgrade() -> None:
    # --- 3 tabelas novas de gasto, mesma forma (padrao ja usado em roteiro_*) ---
    for tabela, coluna_fk, tabela_recurso in (
        ('funcionario_gasto', 'funcionario_id', 'funcionario'),
        ('maquina_gasto', 'maquina_id', 'maquina'),
        ('ambiente_gasto', 'ambiente_id', 'ambiente'),
    ):
        op.create_table(
            tabela,
            sa.Column('id', sa.Integer(), nullable=False),
            sa.Column(coluna_fk, sa.Integer(), nullable=False),
            sa.Column('plano_de_contas_id', sa.Integer(), nullable=False),
            sa.Column('desembolso', sa.Numeric(precision=14, scale=6), nullable=False),
            sa.Column('retencao', sa.Numeric(precision=14, scale=6), nullable=False),
            sa.ForeignKeyConstraint([coluna_fk], [f'{tabela_recurso}.id'], ),
            sa.ForeignKeyConstraint(['plano_de_contas_id'], ['plano_de_contas.id'], ),
            sa.PrimaryKeyConstraint('id'),
        )

    # backfill: placeholder de Plano de Contas para os dados de exemplo pre-existentes
    op.execute(
        """
        INSERT INTO plano_de_contas (codigo, nome, tipo)
        SELECT 'PC-BACKFILL', 'Migrado automaticamente (revisar)', 'custo'
        WHERE (EXISTS (SELECT 1 FROM funcionario) OR EXISTS (SELECT 1 FROM maquina)
               OR EXISTS (SELECT 1 FROM ambiente))
          AND NOT EXISTS (SELECT 1 FROM plano_de_contas WHERE codigo = 'PC-BACKFILL')
        """
    )

    # backfill: 1 linha de Gasto por recurso existente, preservando o total atual
    op.execute(
        """
        INSERT INTO funcionario_gasto (funcionario_id, plano_de_contas_id, desembolso, retencao)
        SELECT f.id, (SELECT id FROM plano_de_contas WHERE codigo = 'PC-BACKFILL'), f.custo_mensal, 0
        FROM funcionario f
        """
    )
    op.execute(
        """
        INSERT INTO maquina_gasto (maquina_id, plano_de_contas_id, desembolso, retencao)
        SELECT m.id, (SELECT id FROM plano_de_contas WHERE codigo = 'PC-BACKFILL'),
               m.manutencao_mensal + m.custo_energia_mensal,
               CASE WHEN m.meses_depreciacao <> 0 THEN m.valor_compra / m.meses_depreciacao ELSE 0 END
        FROM maquina m
        """
    )
    op.execute(
        """
        INSERT INTO ambiente_gasto (ambiente_id, plano_de_contas_id, desembolso, retencao)
        SELECT a.id, (SELECT id FROM plano_de_contas WHERE codigo = 'PC-BACKFILL'), a.valor_rateado_mensal, 0
        FROM ambiente a
        """
    )

    # --- funcionario: novos campos (subordinacao, horas contratadas/absenteismo) ---
    op.add_column('funcionario', sa.Column('subordinado_a_id', sa.Integer(), nullable=True))
    op.create_foreign_key(
        'funcionario_subordinado_a_id_fkey', 'funcionario', 'funcionario', ['subordinado_a_id'], ['id']
    )
    op.add_column('funcionario', sa.Column('horas_semanais', sa.Numeric(precision=14, scale=6), nullable=True))
    op.add_column(
        'funcionario', sa.Column('horas_contratadas_mensais', sa.Numeric(precision=14, scale=6), nullable=True)
    )
    op.add_column('funcionario', sa.Column('absenteismo_pct', sa.Numeric(precision=6, scale=4), nullable=True))
    op.execute(
        """
        UPDATE funcionario SET horas_contratadas_mensais = horas_uteis_mensais, absenteismo_pct = 0
        WHERE horas_contratadas_mensais IS NULL
        """
    )
    op.alter_column('funcionario', 'horas_contratadas_mensais', nullable=False)
    op.alter_column('funcionario', 'absenteismo_pct', nullable=False)

    op.drop_column('funcionario', 'custo_mensal')
    op.drop_column('funcionario', 'horas_uteis_mensais')

    # --- maquina: colunas antigas somem (viram Gasto) ---
    op.drop_column('maquina', 'valor_compra')
    op.drop_column('maquina', 'meses_depreciacao')
    op.drop_column('maquina', 'manutencao_mensal')
    op.drop_column('maquina', 'custo_energia_mensal')

    # --- ambiente: coluna antiga some (vira Gasto) ---
    op.drop_column('ambiente', 'valor_rateado_mensal')


def downgrade() -> None:
    # ambiente: recria valor_rateado_mensal a partir da soma dos Gastos
    op.add_column('ambiente', sa.Column('valor_rateado_mensal', sa.Numeric(precision=14, scale=6), nullable=True))
    op.execute(
        """
        UPDATE ambiente SET valor_rateado_mensal = COALESCE(
            (SELECT SUM(desembolso + retencao) FROM ambiente_gasto WHERE ambiente_gasto.ambiente_id = ambiente.id), 0
        )
        """
    )
    op.alter_column('ambiente', 'valor_rateado_mensal', nullable=False)

    # maquina: recria colunas antigas; lossy — nao ha mais como saber o split deprec./manut./energia,
    # preserva so o TOTAL (soma dos Gastos) em manutencao_mensal, zera o resto
    op.add_column('maquina', sa.Column('valor_compra', sa.Numeric(precision=14, scale=6), nullable=True))
    op.add_column('maquina', sa.Column('meses_depreciacao', sa.Integer(), nullable=True))
    op.add_column('maquina', sa.Column('manutencao_mensal', sa.Numeric(precision=14, scale=6), nullable=True))
    op.add_column('maquina', sa.Column('custo_energia_mensal', sa.Numeric(precision=14, scale=6), nullable=True))
    op.execute(
        """
        UPDATE maquina SET
            valor_compra = 0,
            meses_depreciacao = 1,
            manutencao_mensal = COALESCE(
                (SELECT SUM(desembolso + retencao) FROM maquina_gasto WHERE maquina_gasto.maquina_id = maquina.id), 0
            ),
            custo_energia_mensal = 0
        """
    )
    op.alter_column('maquina', 'valor_compra', nullable=False)
    op.alter_column('maquina', 'meses_depreciacao', nullable=False)
    op.alter_column('maquina', 'manutencao_mensal', nullable=False)
    op.alter_column('maquina', 'custo_energia_mensal', nullable=False)

    # funcionario: recria custo_mensal/horas_uteis_mensais a partir dos Gastos/formula
    op.add_column('funcionario', sa.Column('custo_mensal', sa.Numeric(precision=14, scale=6), nullable=True))
    op.add_column('funcionario', sa.Column('horas_uteis_mensais', sa.Numeric(precision=14, scale=6), nullable=True))
    op.execute(
        """
        UPDATE funcionario SET
            custo_mensal = COALESCE(
                (SELECT SUM(desembolso + retencao) FROM funcionario_gasto
                 WHERE funcionario_gasto.funcionario_id = funcionario.id), 0
            ),
            horas_uteis_mensais = horas_contratadas_mensais * (1 - absenteismo_pct)
        """
    )
    op.alter_column('funcionario', 'custo_mensal', nullable=False)
    op.alter_column('funcionario', 'horas_uteis_mensais', nullable=False)

    op.drop_constraint('funcionario_subordinado_a_id_fkey', 'funcionario', type_='foreignkey')
    op.drop_column('funcionario', 'subordinado_a_id')
    op.drop_column('funcionario', 'horas_semanais')
    op.drop_column('funcionario', 'horas_contratadas_mensais')
    op.drop_column('funcionario', 'absenteismo_pct')

    op.drop_table('ambiente_gasto')
    op.drop_table('maquina_gasto')
    op.drop_table('funcionario_gasto')
