-- ============================================================================
-- Migration 017 — AP#10.1: Triggers BEFORE de protecao contra edicao em
--                 apuracao fechada (rede de seguranca final do AP#10).
-- ============================================================================
-- PRD:   docs/PRDs/PRD-0002-modelo-agente/PRD-TECNICA-0002-modelo-agente.md
-- Card:  AP#10.1 (roadmap) — estrategia long-tail do AP#10
-- Data:  08/05/2026 noite
-- Decidido por: Giovanny Porto (Stakeholder Leader) em batch 08/05/2026 noite
--
-- ============================================================================
-- ESCOPO
-- ============================================================================
-- 6 triggers BEFORE em 3 tabelas (UPDATE + DELETE per tabela):
--   1. trg_agente_proteger_pedido_bu        (BEFORE UPDATE em tbl_Pedido)
--   2. trg_agente_proteger_pedido_bd        (BEFORE DELETE em tbl_Pedido)
--   3. trg_agente_proteger_boleto_bu        (BEFORE UPDATE em tbl_Boleto)
--   4. trg_agente_proteger_boleto_bd        (BEFORE DELETE em tbl_Boleto)
--   5. trg_agente_proteger_faturamento_bu   (BEFORE UPDATE em tbl_Faturamento)
--   6. trg_agente_proteger_faturamento_bd   (BEFORE DELETE em tbl_Faturamento)
--
-- Cada trigger:
--   * Verifica se OLD.<pk> aparece em agente_apuracao_itens vinculado a uma
--     apuracao com status_ciclo='fechada'.
--   * Se sim -> SIGNAL SQLSTATE '45000' com mensagem 'APURACAO_FECHADA_AFETADA'.
--   * Se nao -> deixa a operacao seguir normal.
--
-- Filosofia: ROW-LEVEL (qualquer UPDATE/DELETE bloqueia, independente da coluna).
-- Conservador por design — espelha o helper PHP agente_proteger_edicao() que
-- trabalha row-level. False positives em edicoes benignas (ex.: update de obs
-- em pedido fechado) sao aceitaveis: operador deve usar o fluxo de "solicitar
-- reabertura" pra qualquer mudanca em apuracao fechada.
--
-- ============================================================================
-- POR QUE A MIGRATION USA DELIMITER (precisa mysql CLI, nao runner PDO)
-- ============================================================================
-- Triggers com SIGNAL exigem BEGIN/END/IF — sintaxe que o runner PDO nao aceita
-- (memory: feedback_pdo_runner_nao_suporta_delimiter.md).
--
-- Aplicacao manual:
--   /Applications/MAMP/Library/bin/mysql80/bin/mysql -h 127.0.0.1 -P 3306 \
--     -u root -proot tefnet_erp \
--     < sql/migrations/20260508_017_create_triggers_protecao_apuracao_fechada.up.sql
--
--   php sql/migrate.php register-applied 20260508_017_create_triggers_protecao_apuracao_fechada
--
-- ============================================================================
-- INTERACAO COM O TRIGGER trg_agente_snapshot_faturamento_bi (Migration 014)
-- ============================================================================
-- A Migration 014 ja criou trg_agente_snapshot_faturamento_bi (BEFORE INSERT em
-- tbl_Faturamento). Esta migration adiciona BEFORE UPDATE/DELETE — eventos
-- distintos, sem conflito. MySQL aceita 1 trigger por (tabela, evento, momento).
-- ============================================================================

DELIMITER $$

-- ----------------------------------------------------------------------------
-- 1) tbl_Pedido — BEFORE UPDATE
-- ----------------------------------------------------------------------------
DROP TRIGGER IF EXISTS trg_agente_proteger_pedido_bu$$

CREATE TRIGGER trg_agente_proteger_pedido_bu
BEFORE UPDATE ON tbl_Pedido
FOR EACH ROW
BEGIN
    IF EXISTS (
        SELECT 1
        FROM agente_apuracao_itens i
        JOIN agente_apuracao_periodos p ON p.id = i.apuracao_id
        WHERE i.cod_Pedido_snap = OLD.cod_Pedido
          AND p.status_ciclo = 'fechada'
    ) THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'APURACAO_FECHADA_AFETADA: edicao em tbl_Pedido bloqueada — pedido vinculado a apuracao fechada (AP#10.1)';
    END IF;
END$$

-- ----------------------------------------------------------------------------
-- 2) tbl_Pedido — BEFORE DELETE
-- ----------------------------------------------------------------------------
DROP TRIGGER IF EXISTS trg_agente_proteger_pedido_bd$$

CREATE TRIGGER trg_agente_proteger_pedido_bd
BEFORE DELETE ON tbl_Pedido
FOR EACH ROW
BEGIN
    IF EXISTS (
        SELECT 1
        FROM agente_apuracao_itens i
        JOIN agente_apuracao_periodos p ON p.id = i.apuracao_id
        WHERE i.cod_Pedido_snap = OLD.cod_Pedido
          AND p.status_ciclo = 'fechada'
    ) THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'APURACAO_FECHADA_AFETADA: delete em tbl_Pedido bloqueado — pedido vinculado a apuracao fechada (AP#10.1)';
    END IF;
END$$

-- ----------------------------------------------------------------------------
-- 3) tbl_Boleto — BEFORE UPDATE
-- ----------------------------------------------------------------------------
DROP TRIGGER IF EXISTS trg_agente_proteger_boleto_bu$$

CREATE TRIGGER trg_agente_proteger_boleto_bu
BEFORE UPDATE ON tbl_Boleto
FOR EACH ROW
BEGIN
    IF EXISTS (
        SELECT 1
        FROM agente_apuracao_itens i
        JOIN agente_apuracao_periodos p ON p.id = i.apuracao_id
        WHERE i.id_titulo_snap = OLD.id
          AND i.fonte_titulo = 'boleto'
          AND p.status_ciclo = 'fechada'
    ) THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'APURACAO_FECHADA_AFETADA: edicao em tbl_Boleto bloqueada — titulo vinculado a apuracao fechada (AP#10.1)';
    END IF;
END$$

-- ----------------------------------------------------------------------------
-- 4) tbl_Boleto — BEFORE DELETE
-- ----------------------------------------------------------------------------
DROP TRIGGER IF EXISTS trg_agente_proteger_boleto_bd$$

CREATE TRIGGER trg_agente_proteger_boleto_bd
BEFORE DELETE ON tbl_Boleto
FOR EACH ROW
BEGIN
    IF EXISTS (
        SELECT 1
        FROM agente_apuracao_itens i
        JOIN agente_apuracao_periodos p ON p.id = i.apuracao_id
        WHERE i.id_titulo_snap = OLD.id
          AND i.fonte_titulo = 'boleto'
          AND p.status_ciclo = 'fechada'
    ) THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'APURACAO_FECHADA_AFETADA: delete em tbl_Boleto bloqueado — titulo vinculado a apuracao fechada (AP#10.1)';
    END IF;
END$$

-- ----------------------------------------------------------------------------
-- 5) tbl_Faturamento — BEFORE UPDATE
-- ----------------------------------------------------------------------------
DROP TRIGGER IF EXISTS trg_agente_proteger_faturamento_bu$$

CREATE TRIGGER trg_agente_proteger_faturamento_bu
BEFORE UPDATE ON tbl_Faturamento
FOR EACH ROW
BEGIN
    IF EXISTS (
        SELECT 1
        FROM agente_apuracao_itens i
        JOIN agente_apuracao_periodos p ON p.id = i.apuracao_id
        WHERE i.id_titulo_snap = OLD.id
          AND i.fonte_titulo = 'faturamento'
          AND p.status_ciclo = 'fechada'
    ) THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'APURACAO_FECHADA_AFETADA: edicao em tbl_Faturamento bloqueada — titulo vinculado a apuracao fechada (AP#10.1)';
    END IF;
END$$

-- ----------------------------------------------------------------------------
-- 6) tbl_Faturamento — BEFORE DELETE
-- ----------------------------------------------------------------------------
DROP TRIGGER IF EXISTS trg_agente_proteger_faturamento_bd$$

CREATE TRIGGER trg_agente_proteger_faturamento_bd
BEFORE DELETE ON tbl_Faturamento
FOR EACH ROW
BEGIN
    IF EXISTS (
        SELECT 1
        FROM agente_apuracao_itens i
        JOIN agente_apuracao_periodos p ON p.id = i.apuracao_id
        WHERE i.id_titulo_snap = OLD.id
          AND i.fonte_titulo = 'faturamento'
          AND p.status_ciclo = 'fechada'
    ) THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'APURACAO_FECHADA_AFETADA: delete em tbl_Faturamento bloqueado — titulo vinculado a apuracao fechada (AP#10.1)';
    END IF;
END$$

DELIMITER ;

-- ============================================================================
-- VERIFICACAO POS-MIGRATION
-- ============================================================================
-- 1) Confirmar 6 triggers criados:
--    SELECT TRIGGER_NAME, EVENT_MANIPULATION, EVENT_OBJECT_TABLE, ACTION_TIMING
--    FROM information_schema.TRIGGERS
--    WHERE TRIGGER_SCHEMA='tefnet_erp' AND TRIGGER_NAME LIKE 'trg_agente_proteger_%'
--    ORDER BY EVENT_OBJECT_TABLE, EVENT_MANIPULATION;
--
-- 2) Smoke teste — UPDATE em pedido SEM apuracao fechada deve passar:
--    UPDATE tbl_Pedido SET obs='trigger smoke 1' WHERE cod_Pedido = <id_sem_apuracao>;
--    -> deve atualizar normalmente.
--
-- 3) Smoke teste — UPDATE em pedido COM apuracao fechada deve falhar com 1644:
--    -- Setup: garantir apuracao fechada com cod_Pedido_snap conhecido
--    UPDATE tbl_Pedido SET obs='trigger smoke 2' WHERE cod_Pedido = <id_em_apuracao_fechada>;
--    -> ERROR 1644 (45000): APURACAO_FECHADA_AFETADA: edicao em tbl_Pedido bloqueada...
--
-- 4) Confirmar que trigger de Migration 014 (snapshot BEFORE INSERT) continua intacto:
--    SHOW TRIGGERS LIKE 'tbl_Faturamento';
--    -> deve listar AMBOS: trg_agente_snapshot_faturamento_bi (BI) E
--                        trg_agente_proteger_faturamento_bu (BU) E
--                        trg_agente_proteger_faturamento_bd (BD).
