-- =============================================================================
-- sar-triggers.sql
-- Triggers de integração SAR → ERP (schema sig/gestao no banco libreplast)
--
-- Execução: psql -U postgres -d libreplast -f scripts/sar-triggers.sql
--
-- CONTEÚDO:
--   1. ALTER TABLE sar.pedidos — adiciona erp_id_pedido para rastrear ref ERP
--   2. fn_sync_pedido_aprovado_to_erp — replica pedido aprovado em sig.pedidos
--   3. trg_pedido_aprovado — dispara fn acima ao aprovar (situa 1→2)
--   4. sar.clientes_novos — tabela staging de clientes criados pelo rep
--   5. fn_sync_cliente_to_erp — replica cliente em sig.corrent
--   6. trg_cliente_novo — dispara fn acima no INSERT em clientes_novos
-- =============================================================================

-- ---------------------------------------------------------------------------
-- 1. Coluna de referência ERP no pedido SAR
-- ---------------------------------------------------------------------------
ALTER TABLE sar.pedidos
    ADD COLUMN IF NOT EXISTS erp_id_pedido INTEGER;

CREATE INDEX IF NOT EXISTS idx_sar_ped_erp_id ON sar.pedidos(erp_id_pedido)
    WHERE erp_id_pedido IS NOT NULL;

-- ---------------------------------------------------------------------------
-- 2. Função: replicar pedido aprovado → sig.pedidos + sig.peditens
--
-- Dispara quando sar.pedidos.situa muda de qualquer valor para 2 (Aprovado).
-- Insere em sig.pedidos com situa=1 (Pendente ERP) para que o operador
-- da fábrica finalize o lançamento. Grava o id_pedido ERP de volta em
-- sar.pedidos.erp_id_pedido.
--
-- id_tes=48 (Venda de Produção) — padrão SAR. Mudar para 53 se for bonificação.
-- numero: MAX+1 por empresa — mesmo padrão usado pelo SIG Desktop.
-- ---------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION sar.fn_sync_pedido_aprovado_to_erp()
RETURNS TRIGGER LANGUAGE plpgsql AS $$
DECLARE
    v_numero        INTEGER;
    v_id_pedido_erp INTEGER;
    v_cod_pauta     INTEGER;
    v_item          RECORD;
    v_id_st         INTEGER;
    v_endereco      TEXT;
    v_bairro        TEXT;
    v_municipio     TEXT;
    v_estado        TEXT;
    v_cep           TEXT;
BEGIN
    -- Só dispara na transição → 2 (Aprovado) e se ainda não sincronizado
    IF NEW.situa <> 2 OR OLD.situa = 2 OR NEW.erp_id_pedido IS NOT NULL THEN
        RETURN NEW;
    END IF;

    -- Lock por empresa para serializar geração do número (FOR UPDATE não
    -- é permitido com funções de agregação no PG 18)
    PERFORM pg_advisory_xact_lock(NEW.id_empresa::bigint);

    SELECT COALESCE(MAX(numero), 0) + 1
      INTO v_numero
      FROM sig.pedidos
     WHERE id_empresa = NEW.id_empresa;

    -- Código da pauta (sig usa codigo, SAR armazena id_pauta)
    SELECT codigo INTO v_cod_pauta
      FROM gestao.pauta
     WHERE id_pauta = NEW.id_pauta
     LIMIT 1;

    -- Endereço de entrega do cliente (do ERP)
    SELECT
        COALESCE(c.endereco, ''),
        COALESCE(c.bairr, ''),
        COALESCE(m.nome, ''),
        COALESCE(m.estado, ''),
        COALESCE(c.cep, '')
    INTO v_endereco, v_bairro, v_municipio, v_estado, v_cep
    FROM sig.corrent c
    LEFT JOIN gestao.municipio m ON m.id_municipio = c.id_municipio
    WHERE c.id_corrent = NEW.id_cliente
    LIMIT 1;

    -- Inserir cabeçalho do pedido no ERP
    INSERT INTO sig.pedidos (
        id_empresa,
        tipo,
        numero,
        data,
        data_emissao,
        num_ped_vendedor,
        id_tes,
        situa,
        id_local,
        clien,
        cod_vendedor,
        cod_pauta,
        cod_formapag,
        e_ender,
        e_bairr,
        e_munic,
        e_estad,
        e_cep,
        conta,
        totpr,
        ipi,
        vl_icms_subst,
        total,
        descp,
        descv,
        com_fat,
        com_rec,
        obs,
        prz_con,
        tx_acrescimo,
        num_ped_sar,
        inf_usuario,
        fconta,
        frete,
        cliente_retira,
        pesob,
        pesol,
        ordem,
        finalidade,
        vol_qtd,
        vol_especie,
        vol_marca,
        vol_numero,
        obs_nf1,
        obs_nf2,
        num_oc,
        usuario_credito,
        num_lacre,
        etiqueta_emitida,
        canc_saldo,
        rec_antecipado,
        guid_sarped,
        redesp_frete,
        prioridade,
        classificacao,
        enviar_email,
        tp_moeda,
        vl_cotacao
    ) VALUES (
        NEW.id_empresa,
        'P',
        v_numero,
        NEW.dt_pedido,
        NEW.dt_pedido,
        NEW.num_ped_sar,            -- num_ped_vendedor = SAR ref
        48,                          -- id_tes: Venda de Produção
        1,                           -- situa ERP: Pendente (operador finaliza)
        0,
        NEW.id_cliente,
        NEW.cod_vendedor,
        COALESCE(v_cod_pauta, 0),
        COALESCE(NEW.cod_formapag, 0),
        COALESCE(v_endereco, ''),
        COALESCE(v_bairro, ''),
        COALESCE(v_municipio, ''),
        COALESCE(v_estado, ''),
        COALESCE(v_cep, ''),
        '',
        NEW.total_produtos,
        NEW.total_ipi,
        NEW.total_icmsst,
        NEW.total,
        NEW.desconto_perc,
        NEW.desconto_valor,
        NEW.comissao,
        0,
        COALESCE(LEFT(NEW.obs, 1024), ''),
        0,
        COALESCE(NEW.acrescimo, 0),
        NEW.num_ped_sar,
        1,                           -- inf_usuario=1: criado pelo SAR
        1,                           -- fconta: CHECK (1,2,3,4,5,6,9) — 1=padrão
        0,
        0,
        0,
        0,
        0,
        ' ',
        '',
        '',
        '',
        '',
        '',
        '',
        ' ',
        '',
        '',
        0,
        0,
        0,
        '',
        0,
        2,
        ' ',
        0,
        0,
        0
    )
    RETURNING id_pedido INTO v_id_pedido_erp;

    -- Inserir itens no ERP
    FOR v_item IN
        SELECT pi.*
          FROM sar.pedido_itens pi
         WHERE pi.id_pedido = NEW.id
         ORDER BY pi.ordem
    LOOP
        -- Situação tributária do produto
        SELECT s.id_st INTO v_id_st
          FROM gestao.produto p
          JOIN gestao.st s ON s.codigo = p.cod_st
         WHERE p.id_erp = v_item.id_produto
           AND p.id_empresa = CASE
                                WHEN NEW.id_empresa > 9000
                                THEN NEW.id_empresa - 9000
                                ELSE NEW.id_empresa
                              END
         LIMIT 1;

        INSERT INTO sig.peditens (
            id_pedido,
            ordem,
            produ,
            id_grade,
            qtd,
            pruni,
            descp,
            descv,
            ipi,
            total,
            comis,
            obs,
            id_st,
            preco_pauta,
            qtd_vasilhame_dev,
            id_integrado,
            qtd_bonificacao,
            num_entrega,
            vl_comissao_und,
            id_acabamento,
            id_vidro,
            largura,
            altura,
            l1, l2, l3, l4,
            h1, h2, h3, h4,
            id_varprod,
            id_vista,
            num_op,
            status,
            vl_icmsst,
            tp_operacao,
            vl_acrescimo,
            tempo_prod_prev,
            preco_ipi,
            vl_flex
        ) VALUES (
            v_id_pedido_erp,
            v_item.ordem,
            v_item.id_produto,
            NULL,
            v_item.qtd,
            v_item.preco_unitario,
            v_item.desconto_perc,
            v_item.desconto_valor,
            v_item.vl_ipi,
            v_item.total,
            v_item.comissao,
            '',
            COALESCE(v_id_st, 0),
            v_item.preco_pauta,
            0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0,
            0, 0, 0, 0,
            0,
            0,
            0,
            1,              -- status=1: item ativo/normal
            v_item.vl_icmsst,
            0,
            0,
            0,
            v_item.preco_com_ipi,
            v_item.vl_flex
        );
    END LOOP;

    -- Gravar referência ERP de volta no pedido SAR
    UPDATE sar.pedidos
       SET erp_id_pedido = v_id_pedido_erp
     WHERE id = NEW.id;

    RETURN NEW;
END;
$$;

-- Criar (ou recriar) o trigger
DROP TRIGGER IF EXISTS trg_pedido_aprovado ON sar.pedidos;

CREATE TRIGGER trg_pedido_aprovado
    AFTER UPDATE OF situa ON sar.pedidos
    FOR EACH ROW
    EXECUTE FUNCTION sar.fn_sync_pedido_aprovado_to_erp();

-- ---------------------------------------------------------------------------
-- 4. Tabela staging de clientes novos criados pelo SAR
--
-- O rep preenche os campos obrigatórios e o trigger replica em sig.corrent.
-- Após a replicação, id_corrent_erp é preenchido com o id gerado pelo ERP.
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS sar.clientes_novos (
    id              UUID        PRIMARY KEY DEFAULT gen_random_uuid(),
    id_empresa      INTEGER     NOT NULL,
    cod_vendedor    INTEGER     NOT NULL,

    -- Dados principais
    nome            VARCHAR(40)  NOT NULL,
    razao           VARCHAR(65)  NOT NULL,
    pesso           SMALLINT     NOT NULL DEFAULT 1,  -- 0=PJ 1=PF
    consfinal       SMALLINT     NOT NULL DEFAULT 0,
    cgcpf           VARCHAR(18),
    suf_cgcpf       VARCHAR(3)   NOT NULL DEFAULT '',
    inscr           VARCHAR(18)  NOT NULL DEFAULT '',
    indicador_ie    SMALLINT,      -- 1=contribuinte 2=isento 9=não contribuinte

    -- Endereço
    endereco        VARCHAR(60)  NOT NULL DEFAULT '',
    num_endereco    VARCHAR(10)  NOT NULL DEFAULT '',
    bairro          VARCHAR(60)  NOT NULL DEFAULT '',
    id_municipio    INTEGER      NOT NULL,
    cep             VARCHAR(9)   NOT NULL DEFAULT '',

    -- Contato
    ddd             VARCHAR(4)   NOT NULL DEFAULT '',
    telefone        VARCHAR(35)  NOT NULL DEFAULT '',
    email           VARCHAR(80)  NOT NULL DEFAULT '',

    -- Comercial
    limite_credito  NUMERIC(15,2) NOT NULL DEFAULT 0,
    cod_formapag    INTEGER,
    cod_pauta       INTEGER,

    -- Resultado após sync
    id_corrent_erp  INTEGER,
    sincronizado    BOOLEAN      NOT NULL DEFAULT FALSE,
    erro_sync       TEXT,

    created_at      TIMESTAMP    NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_sar_clinovos_empresa  ON sar.clientes_novos(id_empresa);
CREATE INDEX IF NOT EXISTS idx_sar_clinovos_vend     ON sar.clientes_novos(cod_vendedor);
CREATE INDEX IF NOT EXISTS idx_sar_clinovos_sync     ON sar.clientes_novos(sincronizado);

-- ---------------------------------------------------------------------------
-- 5. Função: replicar cliente novo → sig.corrent
--
-- Campos obrigatórios NOT NULL sem default em sig.corrent recebem '' (char)
-- ou 0 (int). O ERP aceita esses defaults — é o mesmo padrão do SIG Desktop
-- ao cadastrar cliente mínimo.
-- ---------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION sar.fn_sync_cliente_to_erp()
RETURNS TRIGGER LANGUAGE plpgsql AS $$
DECLARE
    v_id_corrent INTEGER;
    v_cgcpf      CHAR(18);
BEGIN
    BEGIN
        -- NULLIF evita conflito no unique index key_corrent_cgcpf quando cgcpf é vazio
        v_cgcpf := NULLIF(TRIM(COALESCE(NEW.cgcpf, '')), '');

        INSERT INTO sig.corrent (
            ativo, pesso, consfinal, cgcpf, suf_cgcpf, inscr, nome, razao,
            endereco, cxpostal, compl, bairr, id_municipio, cep,
            e_ender, e_bairr, e_cep, c_ender, c_bairr, c_cep,
            e_mail, grupo_eco, no_reg, hor_descarga,
            fat_anul, cap_social, cap_realiz, cap_aberto, con_ac_privado, con_ac_nacional,
            ramo_ativ, cod_ativ_ir, no_empregados,
            importa, p_importa, exporta, p_exporta,
            princ_produ1, princ_produ2, princ_produ3, perc_vendas1, perc_vendas2, perc_vendas3,
            www, banc1, banc2, banc3, agen1, agen2, agen3, nagen1, nagen2, nagen3,
            ct_nu, ct_se, ci1, ci2, orgex, uf,
            ddd, telef, fax, data, cod_vendedor, conta,
            c_dm_nascto, c_fone, con_f, f_dm_nascto, f_fone, c_ctb, c_ctb_consig,
            -- campos pessoais (obrigatórios sem default)
            sexo, e_civ, pai, mae, conju, ocupa, c_spc, natur,
            t_ser, l_tra, t_end, inscr_pro, classe,
            tolatr, inscr_suframa, lei_livre, codigo,
            aviso_protesto, codigo_vend_prep, id_tipo,
            i_ban, i_com, obs,
            -- comercial
            limcred, indicador_ie, cod_formapag, cod_pauta
        ) VALUES (
            1, NEW.pesso, NEW.consfinal,
            v_cgcpf, COALESCE(NEW.suf_cgcpf, ''), COALESCE(NEW.inscr, ''),
            COALESCE(LEFT(NEW.nome, 40), ''), LEFT(NEW.razao, 65),
            COALESCE(LEFT(NEW.endereco, 60), ''), 0, '',
            COALESCE(LEFT(NEW.bairro, 60), ''), NEW.id_municipio, COALESCE(NEW.cep, ''),
            COALESCE(LEFT(NEW.endereco, 60), ''), COALESCE(LEFT(NEW.bairro, 60), ''), COALESCE(NEW.cep, ''),
            COALESCE(LEFT(NEW.endereco, 60), ''), COALESCE(LEFT(NEW.bairro, 60), ''), COALESCE(NEW.cep, ''),
            COALESCE(LEFT(NEW.email, 80), ''), '', '', '',
            0, 0, 0, 0, 0, 0,
            '', 0, 0,
            0, 0, 0, 0,
            '', '', '', 0, 0, 0,
            '', 0, 0, 0, '', '', '', '', '', '',
            0, 0, '', 0, '', '',
            COALESCE(NEW.ddd, ''), COALESCE(LEFT(NEW.telefone, 35), ''), '', CURRENT_DATE,
            NEW.cod_vendedor, '',
            NULL, '', '', NULL, '', 0, 0,
            -- campos pessoais com defaults neutros
            0, 0, '', '', '', '', '', '',
            0, '', 0, '', '',
            0, '', '', '',
            0, 0, 0,
            '', '', '',
            -- comercial
            COALESCE(NEW.limite_credito, 0), NEW.indicador_ie, NEW.cod_formapag, NEW.cod_pauta
        )
        RETURNING id_corrent INTO v_id_corrent;

        UPDATE sar.clientes_novos
           SET id_corrent_erp = v_id_corrent,
               sincronizado   = TRUE,
               erro_sync      = NULL
         WHERE id = NEW.id;

    EXCEPTION WHEN OTHERS THEN
        -- Registra o erro sem abortar — rep vê o status na UI
        UPDATE sar.clientes_novos
           SET sincronizado = FALSE,
               erro_sync    = SQLERRM
         WHERE id = NEW.id;
    END;

    RETURN NEW;
END;
$$;

-- Criar (ou recriar) o trigger
DROP TRIGGER IF EXISTS trg_cliente_novo ON sar.clientes_novos;

CREATE TRIGGER trg_cliente_novo
    AFTER INSERT ON sar.clientes_novos
    FOR EACH ROW
    EXECUTE FUNCTION sar.fn_sync_cliente_to_erp();

-- ---------------------------------------------------------------------------
-- 7. Tabela staging de contatos criados pelo rep
--
-- id_entidade em gestao.contato é CHAR(20) — recebe id_corrent::text (auto-pad).
-- whatsapp aqui é o número que será usado para envio via ChatWoot.
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS sar.contatos_novos (
    id              UUID         PRIMARY KEY DEFAULT gen_random_uuid(),
    id_empresa      INTEGER      NOT NULL,
    cod_vendedor    INTEGER      NOT NULL,
    id_corrent      INTEGER      NOT NULL,

    nome            VARCHAR(100) NOT NULL,
    empresa         VARCHAR(100),
    cargo           VARCHAR(100),
    departamento    VARCHAR(100),
    dt_aniversario  DATE,
    telefone        VARCHAR(20),
    ramal           VARCHAR(10),
    celular         VARCHAR(20),
    whatsapp        VARCHAR(20),
    email           VARCHAR(150),
    anotacoes       TEXT,

    id_contato_erp  INTEGER,
    sincronizado    BOOLEAN      NOT NULL DEFAULT FALSE,
    erro_sync       TEXT,
    created_at      TIMESTAMP    NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_sar_ctnov_corrent ON sar.contatos_novos(id_corrent);
CREATE INDEX IF NOT EXISTS idx_sar_ctnov_empresa ON sar.contatos_novos(id_empresa);
CREATE INDEX IF NOT EXISTS idx_sar_ctnov_vend    ON sar.contatos_novos(cod_vendedor);
CREATE INDEX IF NOT EXISTS idx_sar_ctnov_sync    ON sar.contatos_novos(sincronizado);

-- ---------------------------------------------------------------------------
-- 8. Função: replicar contato → gestao.contato
-- ---------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION sar.fn_sync_contato_to_erp()
RETURNS TRIGGER LANGUAGE plpgsql AS $fn$
DECLARE
    v_id_contato  INTEGER;
    v_id_empresa  INTEGER;
BEGIN
    -- Normaliza empresa fiscal (9001) → empresa gerencial (1), padrão do ERP
    v_id_empresa := CASE WHEN NEW.id_empresa > 9000
                         THEN NEW.id_empresa - 9000
                         ELSE NEW.id_empresa END;

    BEGIN
        INSERT INTO gestao.contato (
            id_empresa, id_entidade,
            nome, empresa, cargo, departamento,
            dt_aniversario,
            telefone, ramal, celular, whatsapp, email,
            ativo, anotacoes
        ) VALUES (
            v_id_empresa,
            'COR#' || NEW.id_corrent::text,   -- formato nativo do ERP
            COALESCE(LEFT(NEW.nome, 100), ''),
            LEFT(NEW.empresa, 100),
            LEFT(NEW.cargo, 100),
            LEFT(NEW.departamento, 100),
            NEW.dt_aniversario,
            LEFT(NEW.telefone, 20),
            LEFT(NEW.ramal, 10),
            LEFT(NEW.celular, 20),
            LEFT(NEW.whatsapp, 20),
            LEFT(NEW.email, 150),
            1,
            NEW.anotacoes
        )
        RETURNING id_contato INTO v_id_contato;

        UPDATE sar.contatos_novos
           SET id_contato_erp = v_id_contato,
               sincronizado   = TRUE,
               erro_sync      = NULL
         WHERE id = NEW.id;

    EXCEPTION WHEN OTHERS THEN
        UPDATE sar.contatos_novos
           SET sincronizado = FALSE,
               erro_sync    = SQLERRM
         WHERE id = NEW.id;
    END;

    RETURN NEW;
END;
$fn$;

-- 9. Trigger
DROP TRIGGER IF EXISTS trg_contato_novo ON sar.contatos_novos;
CREATE TRIGGER trg_contato_novo
    AFTER INSERT ON sar.contatos_novos
    FOR EACH ROW EXECUTE FUNCTION sar.fn_sync_contato_to_erp();

-- ---------------------------------------------------------------------------
-- Verificação final
-- ---------------------------------------------------------------------------
SELECT
    trigger_name,
    event_object_schema || '.' || event_object_table AS tabela,
    event_manipulation AS evento,
    action_timing AS timing
FROM information_schema.triggers
WHERE trigger_schema = 'sar'
ORDER BY tabela, trigger_name;
