-- Controle transacional de estoque, compras, custos e estornos.
-- Preserva as colunas e tabelas legadas usadas pelo fluxo de vendas.


ALTER TABLE produtos_estoque
    MODIFY COLUMN estoque DECIMAL(18,4) NOT NULL DEFAULT 0,
    MODIFY COLUMN estoque_minimo DECIMAL(18,4) NULL,
    MODIFY COLUMN preco_venda DECIMAL(18,2) NOT NULL DEFAULT 0,
    MODIFY COLUMN preco_custo DECIMAL(18,6) NULL,
    ADD COLUMN IF NOT EXISTS custo_medio DECIMAL(18,6) NOT NULL DEFAULT 0 AFTER estoque,
    ADD COLUMN IF NOT EXISTS ultima_movimentacao_em DATETIME NULL AFTER preco_custo,
    ADD COLUMN IF NOT EXISTS versao INT UNSIGNED NOT NULL DEFAULT 0 AFTER ultima_movimentacao_em,
    ADD UNIQUE INDEX IF NOT EXISTS uq_produtos_estoque_empresa (id_produto, id_empresa),
    ADD INDEX IF NOT EXISTS idx_produtos_estoque_empresa_saldo (id_empresa, estoque),
    ADD INDEX IF NOT EXISTS idx_produtos_estoque_empresa_custo (id_empresa, custo_medio);

UPDATE produtos_estoque
SET custo_medio = COALESCE(NULLIF(custo_medio, 0), preco_custo, 0)
WHERE custo_medio = 0;

ALTER TABLE operacoes
    ADD COLUMN IF NOT EXISTS codigo VARCHAR(50) NULL AFTER id_conta,
    ADD COLUMN IF NOT EXISTS tipo_movimentacao VARCHAR(10) NOT NULL DEFAULT 'NEUTRA' AFTER mov_estoque,
    ADD COLUMN IF NOT EXISTS finalidade VARCHAR(30) NOT NULL DEFAULT 'OUTRA' AFTER tipo_movimentacao,
    ADD COLUMN IF NOT EXISTS movimenta_estoque CHAR(1) NOT NULL DEFAULT 'N' AFTER finalidade,
    ADD COLUMN IF NOT EXISTS direcao VARCHAR(10) NOT NULL DEFAULT 'NEUTRA' AFTER movimenta_estoque,
    ADD COLUMN IF NOT EXISTS atualiza_custo CHAR(1) NOT NULL DEFAULT 'N' AFTER direcao,
    ADD COLUMN IF NOT EXISTS permite_estoque_negativo CHAR(1) NOT NULL DEFAULT 'N' AFTER atualiza_custo,
    ADD COLUMN IF NOT EXISTS exige_fornecedor CHAR(1) NOT NULL DEFAULT 'N' AFTER permite_estoque_negativo,
    ADD COLUMN IF NOT EXISTS exige_cliente CHAR(1) NOT NULL DEFAULT 'N' AFTER exige_fornecedor,
    ADD COLUMN IF NOT EXISTS id_empresa INT NULL AFTER exige_cliente,
    ADD COLUMN IF NOT EXISTS id_operacao_inversa INT NULL AFTER id_empresa,
    ADD INDEX IF NOT EXISTS idx_operacoes_conta_direcao (id_conta, direcao, status, deletado),
    ADD INDEX IF NOT EXISTS idx_operacoes_empresa (id_empresa),
    ADD INDEX IF NOT EXISTS idx_operacoes_inversa (id_operacao_inversa);

UPDATE operacoes
SET codigo = COALESCE(NULLIF(codigo, ''), CONCAT('OP-', LPAD(id, 6, '0'))),
    tipo_movimentacao = CASE mov_estoque WHEN 'E' THEN 'ENTRADA' WHEN 'S' THEN 'SAIDA' ELSE 'NEUTRA' END,
    direcao = CASE mov_estoque WHEN 'E' THEN 'ENTRADA' WHEN 'S' THEN 'SAIDA' ELSE 'NEUTRA' END,
    movimenta_estoque = CASE WHEN mov_estoque IN ('E', 'S') THEN 'S' ELSE 'N' END,
    finalidade = CASE
        WHEN natureza_operacao = 'V' AND mov_estoque = 'S' THEN 'VENDA'
        WHEN natureza_operacao = 'E' AND mov_estoque = 'E' THEN 'COMPRA'
        WHEN natureza_operacao = 'D' AND mov_estoque = 'E' THEN 'DEVOLUCAO_VENDA'
        WHEN natureza_operacao = 'D' AND mov_estoque = 'S' THEN 'DEVOLUCAO_COMPRA'
        ELSE 'OUTRA'
    END,
    atualiza_custo = CASE WHEN mov_estoque = 'E' THEN 'S' ELSE 'N' END,
    exige_fornecedor = CASE WHEN natureza_operacao = 'E' THEN 'S' ELSE exige_fornecedor END,
    exige_cliente = exige_cliente;

ALTER TABLE operacoes
    MODIFY COLUMN codigo VARCHAR(50) NOT NULL,
    ADD UNIQUE INDEX IF NOT EXISTS uq_operacoes_conta_codigo (id_conta, codigo),
    ADD CONSTRAINT fk_operacoes_empresa FOREIGN KEY (id_empresa) REFERENCES empresas (id) ON DELETE SET NULL,
    ADD CONSTRAINT fk_operacoes_inversa FOREIGN KEY (id_operacao_inversa) REFERENCES operacoes (id) ON DELETE SET NULL;

ALTER TABLE venda_produtos
    MODIFY COLUMN quantidade DECIMAL(18,4) NOT NULL,
    ADD COLUMN IF NOT EXISTS custo_unitario DECIMAL(18,6) NULL AFTER preco,
    ADD COLUMN IF NOT EXISTS custo_total DECIMAL(18,2) NULL AFTER total,
    ADD COLUMN IF NOT EXISTS lucro_estimado DECIMAL(18,2) NULL AFTER custo_total;

ALTER TABLE vendas
    ADD COLUMN IF NOT EXISTS custo_total DECIMAL(18,2) NOT NULL DEFAULT 0 AFTER total,
    ADD COLUMN IF NOT EXISTS lucro_estimado DECIMAL(18,2) NOT NULL DEFAULT 0 AFTER custo_total,
    ADD COLUMN IF NOT EXISTS finalizado_por INT NULL AFTER movimentacao_gerada,
    ADD COLUMN IF NOT EXISTS finalizado_em DATETIME NULL AFTER finalizado_por,
    ADD COLUMN IF NOT EXISTS cancelado_por INT NULL AFTER finalizado_em,
    ADD COLUMN IF NOT EXISTS cancelado_em DATETIME NULL AFTER cancelado_por,
    ADD COLUMN IF NOT EXISTS motivo_cancelamento VARCHAR(500) NULL AFTER cancelado_em,
    ADD COLUMN IF NOT EXISTS estornada CHAR(1) NOT NULL DEFAULT 'N' AFTER motivo_cancelamento,
    ADD COLUMN IF NOT EXISTS chave_finalizacao VARCHAR(191) NULL AFTER estornada,
    ADD UNIQUE INDEX IF NOT EXISTS uq_vendas_chave_finalizacao (chave_finalizacao),
    ADD INDEX IF NOT EXISTS idx_vendas_empresa_status_data (id_empresa, status, dthr_registro),
    ADD INDEX IF NOT EXISTS idx_vendas_finalizado_por (finalizado_por),
    ADD INDEX IF NOT EXISTS idx_vendas_cancelado_por (cancelado_por);

CREATE TABLE IF NOT EXISTS compras (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    id_conta INT NOT NULL,
    id_empresa INT NOT NULL,
    id_fornecedor INT NOT NULL,
    id_operacao INT NOT NULL,
    numero_documento VARCHAR(100) NULL,
    total DECIMAL(18,2) NOT NULL DEFAULT 0,
    status CHAR(2) NOT NULL DEFAULT 'AB',
    observacao TEXT NULL,
    finalizado_por INT NULL,
    finalizado_em DATETIME NULL,
    cancelado_por INT NULL,
    cancelado_em DATETIME NULL,
    motivo_cancelamento VARCHAR(500) NULL,
    estornada CHAR(1) NOT NULL DEFAULT 'N',
    chave_finalizacao VARCHAR(191) NULL,
    deletado CHAR(1) NOT NULL DEFAULT 'N',
    dthr_registro TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    dthr_atualizacao TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (id),
    UNIQUE KEY uq_compras_chave_finalizacao (chave_finalizacao),
    KEY idx_compras_conta_status (id_conta, status, deletado),
    KEY idx_compras_empresa_data (id_empresa, dthr_registro),
    KEY idx_compras_fornecedor (id_fornecedor),
    KEY idx_compras_operacao (id_operacao),
    CONSTRAINT fk_compras_conta FOREIGN KEY (id_conta) REFERENCES contas_usuarios (id),
    CONSTRAINT fk_compras_empresa FOREIGN KEY (id_empresa) REFERENCES empresas (id),
    CONSTRAINT fk_compras_fornecedor FOREIGN KEY (id_fornecedor) REFERENCES fornecedores (id),
    CONSTRAINT fk_compras_operacao FOREIGN KEY (id_operacao) REFERENCES operacoes (id),
    CONSTRAINT fk_compras_finalizado_usuario FOREIGN KEY (finalizado_por) REFERENCES usuarios (id) ON DELETE SET NULL,
    CONSTRAINT fk_compras_cancelado_usuario FOREIGN KEY (cancelado_por) REFERENCES usuarios (id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS compra_itens (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    id_compra BIGINT UNSIGNED NOT NULL,
    id_produto INT NOT NULL,
    quantidade DECIMAL(18,4) NOT NULL,
    custo_unitario DECIMAL(18,6) NOT NULL,
    valor_total DECIMAL(18,2) NOT NULL,
    dthr_registro TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id),
    UNIQUE KEY uq_compra_item_produto (id_compra, id_produto),
    KEY idx_compra_itens_produto (id_produto),
    CONSTRAINT fk_compra_itens_compra FOREIGN KEY (id_compra) REFERENCES compras (id) ON DELETE CASCADE,
    CONSTRAINT fk_compra_itens_produto FOREIGN KEY (id_produto) REFERENCES produtos (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS estoque_movimentacoes (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    id_conta INT NOT NULL,
    id_empresa INT NOT NULL,
    id_produto INT NOT NULL,
    id_operacao INT NULL,
    tipo_movimentacao VARCHAR(30) NOT NULL,
    direcao VARCHAR(10) NOT NULL,
    origem_documento VARCHAR(30) NOT NULL,
    id_documento BIGINT UNSIGNED NULL,
    id_item_origem BIGINT UNSIGNED NULL,
    quantidade DECIMAL(18,4) NOT NULL,
    saldo_anterior DECIMAL(18,4) NOT NULL,
    saldo_posterior DECIMAL(18,4) NOT NULL,
    custo_unitario DECIMAL(18,6) NOT NULL DEFAULT 0,
    custo_medio_anterior DECIMAL(18,6) NOT NULL DEFAULT 0,
    custo_medio_posterior DECIMAL(18,6) NOT NULL DEFAULT 0,
    valor_total DECIMAL(18,2) NOT NULL DEFAULT 0,
    id_usuario INT NULL,
    observacao VARCHAR(500) NULL,
    id_movimentacao_original BIGINT UNSIGNED NULL,
    id_movimentacao_relacionada BIGINT UNSIGNED NULL,
    chave_idempotencia VARCHAR(191) NOT NULL,
    dthr_registro DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
    PRIMARY KEY (id),
    UNIQUE KEY uq_estoque_mov_chave (chave_idempotencia),
    KEY idx_estoque_mov_empresa_data (id_empresa, dthr_registro),
    KEY idx_estoque_mov_produto_data (id_produto, dthr_registro),
    KEY idx_estoque_mov_operacao (id_operacao),
    KEY idx_estoque_mov_origem (origem_documento, id_documento),
    KEY idx_estoque_mov_usuario (id_usuario),
    KEY idx_estoque_mov_original (id_movimentacao_original),
    CONSTRAINT fk_estoque_mov_conta FOREIGN KEY (id_conta) REFERENCES contas_usuarios (id),
    CONSTRAINT fk_estoque_mov_empresa FOREIGN KEY (id_empresa) REFERENCES empresas (id),
    CONSTRAINT fk_estoque_mov_produto FOREIGN KEY (id_produto) REFERENCES produtos (id),
    CONSTRAINT fk_estoque_mov_operacao FOREIGN KEY (id_operacao) REFERENCES operacoes (id) ON DELETE SET NULL,
    CONSTRAINT fk_estoque_mov_usuario FOREIGN KEY (id_usuario) REFERENCES usuarios (id) ON DELETE SET NULL,
    CONSTRAINT fk_estoque_mov_original FOREIGN KEY (id_movimentacao_original) REFERENCES estoque_movimentacoes (id) ON DELETE RESTRICT,
    CONSTRAINT fk_estoque_mov_relacionada FOREIGN KEY (id_movimentacao_relacionada) REFERENCES estoque_movimentacoes (id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS estoque_auditoria (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    id_conta INT NOT NULL,
    id_empresa INT NULL,
    id_usuario INT NULL,
    evento VARCHAR(80) NOT NULL,
    entidade VARCHAR(50) NOT NULL,
    entidade_id BIGINT UNSIGNED NULL,
    dados LONGTEXT NULL,
    ip_origem VARCHAR(45) NULL,
    dthr_registro DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
    PRIMARY KEY (id),
    KEY idx_estoque_auditoria_conta_data (id_conta, dthr_registro),
    KEY idx_estoque_auditoria_empresa_data (id_empresa, dthr_registro),
    KEY idx_estoque_auditoria_entidade (entidade, entidade_id),
    CONSTRAINT fk_estoque_auditoria_conta FOREIGN KEY (id_conta) REFERENCES contas_usuarios (id),
    CONSTRAINT fk_estoque_auditoria_empresa FOREIGN KEY (id_empresa) REFERENCES empresas (id) ON DELETE SET NULL,
    CONSTRAINT fk_estoque_auditoria_usuario FOREIGN KEY (id_usuario) REFERENCES usuarios (id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- Preserva o histórico legado na nova razão sem alterar saldos.
INSERT IGNORE INTO estoque_movimentacoes (
    id_conta, id_empresa, id_produto, id_operacao, tipo_movimentacao, direcao,
    origem_documento, id_documento, quantidade, saldo_anterior, saldo_posterior,
    custo_unitario, custo_medio_anterior, custo_medio_posterior, valor_total,
    observacao, chave_idempotencia, dthr_registro
)
SELECT
    pm.id_conta,
    pm.id_empresa,
    pm.id_produto,
    v.id_operacao,
    'LEGADO',
    CASE pm.tipo WHEN 'E' THEN 'ENTRADA' ELSE 'SAIDA' END,
    CASE WHEN pm.id_venda IS NULL THEN 'LEGADO' ELSE 'VENDA' END,
    pm.id_venda,
    pm.estoque_movimentado,
    pm.estoque_anterior,
    pm.estoque_atual,
    COALESCE(pe.preco_custo, 0),
    COALESCE(pe.custo_medio, pe.preco_custo, 0),
    COALESCE(pe.custo_medio, pe.preco_custo, 0),
    ROUND(pm.estoque_movimentado * COALESCE(pe.preco_custo, 0), 2),
    pm.descricao,
    CONCAT('LEGADO-PRODUTO-MOV-', pm.id),
    pm.dthr_registro
FROM produto_movimentacao pm
LEFT JOIN vendas v ON v.id = pm.id_venda
LEFT JOIN produtos_estoque pe ON pe.id_produto = pm.id_produto AND pe.id_empresa = pm.id_empresa;

INSERT IGNORE INTO estoque_movimentacoes (
    id_conta, id_empresa, id_produto, tipo_movimentacao, direcao,
    origem_documento, id_documento, quantidade, saldo_anterior, saldo_posterior,
    custo_unitario, custo_medio_anterior, custo_medio_posterior, valor_total,
    observacao, chave_idempotencia, dthr_registro
)
SELECT
    p.id_conta,
    pe.id_empresa,
    pe.id_produto,
    'MIGRACAO',
    'NEUTRA',
    'SALDO_MIGRADO',
    pe.id,
    0,
    pe.estoque,
    pe.estoque,
    COALESCE(pe.preco_custo, 0),
    pe.custo_medio,
    pe.custo_medio,
    ROUND(pe.estoque * pe.custo_medio, 2),
    'Posição de estoque existente na implantação do controle transacional.',
    CONCAT('MIGRACAO-SALDO-', pe.id),
    CURRENT_TIMESTAMP(6)
FROM produtos_estoque pe
JOIN produtos p ON p.id = pe.id_produto
WHERE NOT EXISTS (
    SELECT 1 FROM produto_movimentacao pm
    WHERE pm.id_produto = pe.id_produto AND pm.id_empresa = pe.id_empresa
);
