-- +goose Up
-- +goose StatementBegin

-- ═══════════════════════════════════════════════════════════════════════════
-- MIGRATION 030 — MÓDULO FINANCEIRO · PDV · CAIXA
-- Inclui:
--   1. Melhorias na tabela lancamentos (novos campos)
--   2. fin_categorias   — categorias financeiras configuráveis por tenant
--   3. pdv_caixas       — sessões de caixa (abertura/fechamento)
--   4. pdv_movimentos   — sangria, suprimento, reforço, pagamentos no caixa
--   5. pdv_vendas       — venda rápida via PDV (sem pedido formal)
--   6. pdv_venda_itens  — itens de cada venda PDV
--   7. fin_formas_pgto  — formas de pagamento configuráveis (dinheiro, pix, etc.)
--   8. Permissões PDV
-- ═══════════════════════════════════════════════════════════════════════════


-- ───────────────────────────────────────────────────────────────────────────
-- 1. MELHORIAS EM lancamentos
--    Adiciona colunas para rastrear origem (PDV, pedido, orçamento) e
--    forma de pagamento, sem quebrar nada existente.
-- ───────────────────────────────────────────────────────────────────────────

ALTER TABLE lancamentos
    ADD COLUMN IF NOT EXISTS origem       TEXT    DEFAULT 'manual'
        CHECK (origem IN ('manual','pdv','pedido','orcamento','recorrente')),
    ADD COLUMN IF NOT EXISTS origem_id    UUID,                          -- FK polimórfica (pdv_venda.id, pedido.id…)
    ADD COLUMN IF NOT EXISTS forma_pgto   TEXT    DEFAULT 'outros'
        CHECK (forma_pgto IN ('dinheiro','pix','cartao_debito','cartao_credito','boleto','transferencia','cheque','outros')),
    ADD COLUMN IF NOT EXISTS parcelas     SMALLINT DEFAULT 1
        CHECK (parcelas BETWEEN 1 AND 48),
    ADD COLUMN IF NOT EXISTS caixa_id     UUID,                          -- sessão PDV que gerou este lançamento
    ADD COLUMN IF NOT EXISTS fornecedor_id UUID
        REFERENCES fornecedores(id) ON DELETE SET NULL,
    ADD COLUMN IF NOT EXISTS cliente_id   UUID
        REFERENCES clientes(id)    ON DELETE SET NULL,
    ADD COLUMN IF NOT EXISTS tags         TEXT[]  DEFAULT '{}',
    ADD COLUMN IF NOT EXISTS observacoes  TEXT    DEFAULT '',
    ADD COLUMN IF NOT EXISTS recorrente   BOOLEAN DEFAULT false,
    ADD COLUMN IF NOT EXISTS recorrencia  TEXT                           -- 'mensal','semanal','anual'
        CHECK (recorrencia IN ('semanal','mensal','bimestral','trimestral','semestral','anual') OR recorrencia IS NULL);

CREATE INDEX IF NOT EXISTS idx_lancamentos_origem    ON lancamentos (tenant_id, origem, origem_id);
CREATE INDEX IF NOT EXISTS idx_lancamentos_caixa     ON lancamentos (tenant_id, caixa_id);
CREATE INDEX IF NOT EXISTS idx_lancamentos_cliente   ON lancamentos (tenant_id, cliente_id);
CREATE INDEX IF NOT EXISTS idx_lancamentos_fornecedor ON lancamentos (tenant_id, fornecedor_id);
CREATE INDEX IF NOT EXISTS idx_lancamentos_categoria ON lancamentos (tenant_id, categoria);
CREATE INDEX IF NOT EXISTS idx_lancamentos_tags      ON lancamentos USING GIN (tags);


-- ───────────────────────────────────────────────────────────────────────────
-- 2. FIN_CATEGORIAS — categorias financeiras por tenant
--    Cada tenant pode renomear ou adicionar categorias além do padrão.
--    is_sistema = true → pré-criadas na seed, não deletáveis pelo usuário.
-- ───────────────────────────────────────────────────────────────────────────

CREATE TABLE IF NOT EXISTS fin_categorias (
    id           UUID        PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id    UUID        NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    tipo         TEXT        NOT NULL CHECK (tipo IN ('receita','despesa')),
    slug         TEXT        NOT NULL,              -- chave estável (ex: 'vendas', 'salarios')
    nome         TEXT        NOT NULL,              -- label exibida na UI
    cor          TEXT        NOT NULL DEFAULT '#6b7280', -- hex para ícone/badge
    icone        TEXT        NOT NULL DEFAULT '●',
    ordem        SMALLINT    NOT NULL DEFAULT 0,
    ativo        BOOLEAN     NOT NULL DEFAULT true,
    is_sistema   BOOLEAN     NOT NULL DEFAULT false, -- categorias padrão do sistema
    criado_em    TIMESTAMPTZ NOT NULL DEFAULT now(),
    atualizado_em TIMESTAMPTZ NOT NULL DEFAULT now(),
    UNIQUE (tenant_id, slug)
);

CREATE INDEX IF NOT EXISTS idx_fin_cat_tenant_tipo ON fin_categorias (tenant_id, tipo, ordem);

ALTER TABLE fin_categorias ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON fin_categorias
    USING (tenant_id = current_setting('app.tenant_id', true)::uuid);

CREATE TRIGGER trg_fin_cat_updated BEFORE UPDATE ON fin_categorias
    FOR EACH ROW EXECUTE FUNCTION set_updated_at();


-- ───────────────────────────────────────────────────────────────────────────
-- 3. FIN_FORMAS_PGTO — formas de pagamento por tenant
--    Permite habilitar/desabilitar métodos e configurar taxas.
-- ───────────────────────────────────────────────────────────────────────────

CREATE TABLE IF NOT EXISTS fin_formas_pgto (
    id            UUID        PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id     UUID        NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    slug          TEXT        NOT NULL,              -- 'dinheiro','pix','cartao_debito'…
    nome          TEXT        NOT NULL,
    icone         TEXT        NOT NULL DEFAULT '💳',
    taxa_pct      NUMERIC(5,4) NOT NULL DEFAULT 0,  -- ex: 0.0299 = 2,99%
    prazo_dias    SMALLINT    NOT NULL DEFAULT 0,    -- dias para compensar (D+0, D+1…)
    ativo         BOOLEAN     NOT NULL DEFAULT true,
    ordem         SMALLINT    NOT NULL DEFAULT 0,
    is_sistema    BOOLEAN     NOT NULL DEFAULT false,
    criado_em     TIMESTAMPTZ NOT NULL DEFAULT now(),
    atualizado_em TIMESTAMPTZ NOT NULL DEFAULT now(),
    UNIQUE (tenant_id, slug)
);

CREATE INDEX IF NOT EXISTS idx_fin_fp_tenant ON fin_formas_pgto (tenant_id, ativo, ordem);

ALTER TABLE fin_formas_pgto ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON fin_formas_pgto
    USING (tenant_id = current_setting('app.tenant_id', true)::uuid);

CREATE TRIGGER trg_fin_fp_updated BEFORE UPDATE ON fin_formas_pgto
    FOR EACH ROW EXECUTE FUNCTION set_updated_at();


-- ───────────────────────────────────────────────────────────────────────────
-- 4. PDV_CAIXAS — sessões de caixa (turno/operador)
--    Cada abertura de caixa cria uma sessão. O fechamento calcula o
--    saldo final e gera relatório de diferença.
-- ───────────────────────────────────────────────────────────────────────────

CREATE TABLE IF NOT EXISTS pdv_caixas (
    id                  UUID        PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id           UUID        NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    operador_id         UUID        NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
    status              TEXT        NOT NULL DEFAULT 'aberto'
                        CHECK (status IN ('aberto','fechado','suspenso')),

    -- Abertura
    aberto_em           TIMESTAMPTZ NOT NULL DEFAULT now(),
    saldo_abertura      NUMERIC(15,4) NOT NULL DEFAULT 0,    -- troco inicial em dinheiro
    observacao_abertura TEXT          NOT NULL DEFAULT '',

    -- Fechamento
    fechado_em          TIMESTAMPTZ,
    saldo_sistema       NUMERIC(15,4),   -- calculado pelo sistema (soma movimentos)
    saldo_informado     NUMERIC(15,4),   -- o que o operador contou no fechamento
    diferenca           NUMERIC(15,4),   -- saldo_informado - saldo_sistema
    observacao_fechamento TEXT NOT NULL DEFAULT '',

    -- Totalizadores por forma de pagamento (JSONB: {"dinheiro": 150.00, "pix": 300.00})
    totais_pgto         JSONB NOT NULL DEFAULT '{}',

    -- Auditoria
    criado_em           TIMESTAMPTZ NOT NULL DEFAULT now(),
    atualizado_em       TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_pdv_caixas_tenant_status  ON pdv_caixas (tenant_id, status);
CREATE INDEX IF NOT EXISTS idx_pdv_caixas_operador        ON pdv_caixas (tenant_id, operador_id, aberto_em DESC);
CREATE INDEX IF NOT EXISTS idx_pdv_caixas_aberto_em       ON pdv_caixas (tenant_id, aberto_em DESC);

ALTER TABLE pdv_caixas ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON pdv_caixas
    USING (tenant_id = current_setting('app.tenant_id', true)::uuid);

CREATE TRIGGER trg_pdv_caixas_updated BEFORE UPDATE ON pdv_caixas
    FOR EACH ROW EXECUTE FUNCTION set_updated_at();


-- ───────────────────────────────────────────────────────────────────────────
-- 5. PDV_MOVIMENTOS — sangria, suprimento, reforço
--    Movimentos avulsos dentro de uma sessão de caixa que afetam
--    o saldo em dinheiro mas não são vendas.
-- ───────────────────────────────────────────────────────────────────────────

CREATE TABLE IF NOT EXISTS pdv_movimentos (
    id            UUID        PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id     UUID        NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    caixa_id      UUID        NOT NULL REFERENCES pdv_caixas(id) ON DELETE CASCADE,
    operador_id   UUID        NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
    tipo          TEXT        NOT NULL
                  CHECK (tipo IN (
                      'suprimento',   -- adiciona dinheiro ao caixa (reforço de troco)
                      'sangria',      -- retira dinheiro do caixa (segurança)
                      'reforco',      -- complemento autorizado pelo gerente
                      'despesa_pdv'   -- pequena despesa paga direto do caixa
                  )),
    valor         NUMERIC(15,4) NOT NULL CHECK (valor > 0),
    descricao     TEXT          NOT NULL DEFAULT '',
    autorizado_por UUID         REFERENCES users(id) ON DELETE SET NULL,
    criado_em     TIMESTAMPTZ   NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_pdv_mov_caixa    ON pdv_movimentos (tenant_id, caixa_id, criado_em DESC);
CREATE INDEX IF NOT EXISTS idx_pdv_mov_operador ON pdv_movimentos (tenant_id, operador_id, criado_em DESC);

ALTER TABLE pdv_movimentos ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON pdv_movimentos
    USING (tenant_id = current_setting('app.tenant_id', true)::uuid);


-- ───────────────────────────────────────────────────────────────────────────
-- 6. PDV_VENDAS — venda rápida no caixa (sem pedido formal)
--    Para venda de uniformes prontos, kits, bordados avulsos, etc.
-- ───────────────────────────────────────────────────────────────────────────

CREATE TABLE IF NOT EXISTS pdv_vendas (
    id              UUID        PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id       UUID        NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    caixa_id        UUID        NOT NULL REFERENCES pdv_caixas(id) ON DELETE RESTRICT,
    operador_id     UUID        NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
    cliente_id      UUID        REFERENCES clientes(id) ON DELETE SET NULL,

    numero          SERIAL,   -- número sequencial amigável (por tenant via trigger)
    status          TEXT      NOT NULL DEFAULT 'concluida'
                    CHECK (status IN ('aberta','concluida','cancelada','devolvida')),

    subtotal        NUMERIC(15,4) NOT NULL DEFAULT 0,
    desconto_pct    NUMERIC(5,4)  NOT NULL DEFAULT 0,    -- ex: 0.10 = 10%
    desconto_valor  NUMERIC(15,4) NOT NULL DEFAULT 0,
    acrescimo       NUMERIC(15,4) NOT NULL DEFAULT 0,
    total           NUMERIC(15,4) NOT NULL DEFAULT 0,

    -- Pagamento (pode ter mais de uma forma — detalhado em pdv_venda_pgtos)
    forma_pgto      TEXT      NOT NULL DEFAULT 'dinheiro'
                    CHECK (forma_pgto IN ('dinheiro','pix','cartao_debito','cartao_credito','boleto','transferencia','cheque','misto','outros')),
    valor_recebido  NUMERIC(15,4),   -- dinheiro entregue pelo cliente
    troco           NUMERIC(15,4),   -- valor_recebido - total

    -- Campos de rastreabilidade
    lancamento_id   UUID      REFERENCES lancamentos(id) ON DELETE SET NULL, -- lançamento gerado
    observacao      TEXT      NOT NULL DEFAULT '',
    cancelado_por   UUID      REFERENCES users(id) ON DELETE SET NULL,
    motivo_cancelamento TEXT  NOT NULL DEFAULT '',

    criado_em       TIMESTAMPTZ NOT NULL DEFAULT now(),
    atualizado_em   TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_pdv_vendas_tenant_status   ON pdv_vendas (tenant_id, status, criado_em DESC);
CREATE INDEX IF NOT EXISTS idx_pdv_vendas_caixa           ON pdv_vendas (tenant_id, caixa_id);
CREATE INDEX IF NOT EXISTS idx_pdv_vendas_cliente         ON pdv_vendas (tenant_id, cliente_id);
CREATE INDEX IF NOT EXISTS idx_pdv_vendas_lancamento      ON pdv_vendas (lancamento_id);

ALTER TABLE pdv_vendas ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON pdv_vendas
    USING (tenant_id = current_setting('app.tenant_id', true)::uuid);

CREATE TRIGGER trg_pdv_vendas_updated BEFORE UPDATE ON pdv_vendas
    FOR EACH ROW EXECUTE FUNCTION set_updated_at();


-- ───────────────────────────────────────────────────────────────────────────
-- 7. PDV_VENDA_ITENS — itens da venda PDV
--    Cada linha referencia um produto do catálogo (nullable para item livre).
-- ───────────────────────────────────────────────────────────────────────────

CREATE TABLE IF NOT EXISTS pdv_venda_itens (
    id            UUID          PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id     UUID          NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    venda_id      UUID          NOT NULL REFERENCES pdv_vendas(id) ON DELETE CASCADE,
    produto_id    UUID          REFERENCES produtos(id) ON DELETE SET NULL,  -- nullable: item livre
    descricao     TEXT          NOT NULL,          -- nome do produto ou descrição livre
    quantidade    NUMERIC(10,3) NOT NULL DEFAULT 1 CHECK (quantidade > 0),
    unidade       TEXT          NOT NULL DEFAULT 'un',
    preco_unit    NUMERIC(15,4) NOT NULL CHECK (preco_unit >= 0),
    desconto_pct  NUMERIC(5,4)  NOT NULL DEFAULT 0,
    total_item    NUMERIC(15,4) NOT NULL DEFAULT 0, -- quantidade * preco_unit * (1 - desconto_pct)
    criado_em     TIMESTAMPTZ   NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_pdv_itens_venda   ON pdv_venda_itens (tenant_id, venda_id);
CREATE INDEX IF NOT EXISTS idx_pdv_itens_produto ON pdv_venda_itens (tenant_id, produto_id);

ALTER TABLE pdv_venda_itens ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON pdv_venda_itens
    USING (tenant_id = current_setting('app.tenant_id', true)::uuid);


-- ───────────────────────────────────────────────────────────────────────────
-- 8. PDV_VENDA_PGTOS — pagamentos de uma venda (split de pagamento)
--    Para quando o cliente paga parte em dinheiro e parte no pix, etc.
-- ───────────────────────────────────────────────────────────────────────────

CREATE TABLE IF NOT EXISTS pdv_venda_pgtos (
    id          UUID          PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id   UUID          NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    venda_id    UUID          NOT NULL REFERENCES pdv_vendas(id) ON DELETE CASCADE,
    forma_pgto  TEXT          NOT NULL
                CHECK (forma_pgto IN ('dinheiro','pix','cartao_debito','cartao_credito','boleto','transferencia','cheque','outros')),
    valor       NUMERIC(15,4) NOT NULL CHECK (valor > 0),
    parcelas    SMALLINT      NOT NULL DEFAULT 1 CHECK (parcelas BETWEEN 1 AND 48),
    autorizacao TEXT          NOT NULL DEFAULT '', -- NSU, código Pix, etc.
    criado_em   TIMESTAMPTZ   NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_pdv_pgtos_venda ON pdv_venda_pgtos (tenant_id, venda_id);

ALTER TABLE pdv_venda_pgtos ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON pdv_venda_pgtos
    USING (tenant_id = current_setting('app.tenant_id', true)::uuid);


-- ───────────────────────────────────────────────────────────────────────────
-- 9. FUNÇÃO: fn_pdv_fechar_caixa
--    Calcula totais do caixa ao fechar: soma vendas por forma de pagamento,
--    subtrai sangrias, adiciona suprimentos.
--    Chamada pelo handler Go, não precisa ser trigger automático.
-- ───────────────────────────────────────────────────────────────────────────

CREATE OR REPLACE FUNCTION fn_pdv_totais_caixa(p_caixa_id UUID, p_tenant_id UUID)
RETURNS TABLE (
    forma_pgto  TEXT,
    total       NUMERIC(15,4),
    qtd_vendas  BIGINT
) LANGUAGE sql STABLE AS $$
    SELECT
        p.forma_pgto,
        SUM(p.valor)  AS total,
        COUNT(DISTINCT p.venda_id) AS qtd_vendas
    FROM pdv_venda_pgtos p
    INNER JOIN pdv_vendas v ON v.id = p.venda_id
    WHERE p.tenant_id = p_tenant_id
      AND v.caixa_id  = p_caixa_id
      AND v.status    = 'concluida'
    GROUP BY p.forma_pgto
    ORDER BY total DESC
$$;


-- ───────────────────────────────────────────────────────────────────────────
-- 10. FUNÇÃO: fn_pdv_saldo_caixa
--     Retorna o saldo atual em dinheiro de uma sessão aberta.
--     saldo = abertura + suprimentos - sangrias + vendas_dinheiro
-- ───────────────────────────────────────────────────────────────────────────

CREATE OR REPLACE FUNCTION fn_pdv_saldo_caixa(p_caixa_id UUID, p_tenant_id UUID)
RETURNS NUMERIC(15,4) LANGUAGE sql STABLE AS $$
    SELECT
        c.saldo_abertura
        -- suprimentos e reforços somam
        + COALESCE((
            SELECT SUM(valor) FROM pdv_movimentos
            WHERE caixa_id = p_caixa_id AND tenant_id = p_tenant_id
              AND tipo IN ('suprimento','reforco')
          ), 0)
        -- sangrias subtraem
        - COALESCE((
            SELECT SUM(valor) FROM pdv_movimentos
            WHERE caixa_id = p_caixa_id AND tenant_id = p_tenant_id
              AND tipo = 'sangria'
          ), 0)
        -- despesas PDV subtraem
        - COALESCE((
            SELECT SUM(valor) FROM pdv_movimentos
            WHERE caixa_id = p_caixa_id AND tenant_id = p_tenant_id
              AND tipo = 'despesa_pdv'
          ), 0)
        -- vendas em dinheiro somam
        + COALESCE((
            SELECT SUM(p.valor)
            FROM pdv_venda_pgtos p
            INNER JOIN pdv_vendas v ON v.id = p.venda_id
            WHERE v.caixa_id  = p_caixa_id
              AND p.tenant_id = p_tenant_id
              AND v.status    = 'concluida'
              AND p.forma_pgto = 'dinheiro'
          ), 0)
    FROM pdv_caixas c
    WHERE c.id = p_caixa_id AND c.tenant_id = p_tenant_id
$$;


-- ───────────────────────────────────────────────────────────────────────────
-- 11. SEED: categorias financeiras padrão (para novos tenants)
--     Inseridas apenas para o tenant 'sistema' que não existe; na prática
--     o handler Go chama fn_seed_fin_categorias(tenant_id) ao criar tenant.
-- ───────────────────────────────────────────────────────────────────────────

CREATE OR REPLACE FUNCTION fn_seed_fin_categorias(p_tenant_id UUID)
RETURNS void LANGUAGE plpgsql AS $$
BEGIN
    -- Receitas
    INSERT INTO fin_categorias (tenant_id, tipo, slug, nome, cor, icone, ordem, is_sistema)
    VALUES
        (p_tenant_id, 'receita', 'vendas',           'Vendas',              '#107c41', '🛍',  1,  true),
        (p_tenant_id, 'receita', 'servicos',          'Serviços',            '#0f62e0', '⚙',  2,  true),
        (p_tenant_id, 'receita', 'pdv',               'PDV · Caixa',         '#0891b2', '🖥',  3,  true),
        (p_tenant_id, 'receita', 'pedidos',           'Pedidos',             '#7c3aed', '📦', 4,  true),
        (p_tenant_id, 'receita', 'orcamentos',        'Orçamentos',          '#7b5ea7', '📋', 5,  true),
        (p_tenant_id, 'receita', 'faturamento',       'Faturamento / NF',    '#2563eb', '🧾', 6,  true),
        (p_tenant_id, 'receita', 'juros_recebidos',   'Juros Recebidos',     '#059669', '💹', 7,  true),
        (p_tenant_id, 'receita', 'outros_receita',    'Outros (Receita)',     '#6b7280', '➕', 8,  true)
    ON CONFLICT (tenant_id, slug) DO NOTHING;

    -- Despesas
    INSERT INTO fin_categorias (tenant_id, tipo, slug, nome, cor, icone, ordem, is_sistema)
    VALUES
        (p_tenant_id, 'despesa', 'fornecedores',      'Fornecedores',        '#c4314b', '🏭', 1,  true),
        (p_tenant_id, 'despesa', 'materia_prima',     'Matéria-Prima',       '#d97706', '🧵', 2,  true),
        (p_tenant_id, 'despesa', 'producao',          'Custos de Produção',  '#b45309', '⚙',  3,  true),
        (p_tenant_id, 'despesa', 'salarios',          'Salários',            '#7c3aed', '👥', 4,  true),
        (p_tenant_id, 'despesa', 'aluguel',           'Aluguel',             '#6b7280', '🏢', 5,  true),
        (p_tenant_id, 'despesa', 'energia',           'Energia / Água',      '#f59e0b', '⚡', 6,  true),
        (p_tenant_id, 'despesa', 'impostos',          'Impostos',            '#dc2626', '📑', 7,  true),
        (p_tenant_id, 'despesa', 'das',               'DAS / Simples',       '#ef4444', '🏛', 8,  true),
        (p_tenant_id, 'despesa', 'marketing',         'Marketing',           '#8b5cf6', '📣', 9,  true),
        (p_tenant_id, 'despesa', 'manutencao',        'Manutenção',          '#78716c', '🔧', 10, true),
        (p_tenant_id, 'despesa', 'frete',             'Frete / Logística',   '#0284c7', '🚚', 11, true),
        (p_tenant_id, 'despesa', 'outros_despesa',    'Outros (Despesa)',     '#6b7280', '➖', 12, true)
    ON CONFLICT (tenant_id, slug) DO NOTHING;
END;
$$;


-- Seed para formas de pagamento padrão
CREATE OR REPLACE FUNCTION fn_seed_fin_formas_pgto(p_tenant_id UUID)
RETURNS void LANGUAGE plpgsql AS $$
BEGIN
    INSERT INTO fin_formas_pgto (tenant_id, slug, nome, icone, taxa_pct, prazo_dias, ordem, is_sistema)
    VALUES
        (p_tenant_id, 'dinheiro',        'Dinheiro',          '💵', 0.0000, 0,  1, true),
        (p_tenant_id, 'pix',             'Pix',               '⚡', 0.0000, 0,  2, true),
        (p_tenant_id, 'cartao_debito',   'Cartão Débito',     '💳', 0.0150, 1,  3, true),
        (p_tenant_id, 'cartao_credito',  'Cartão Crédito',    '💳', 0.0299, 30, 4, true),
        (p_tenant_id, 'boleto',          'Boleto',            '📄', 0.0200, 3,  5, true),
        (p_tenant_id, 'transferencia',   'Transferência',     '🏦', 0.0000, 1,  6, true),
        (p_tenant_id, 'cheque',          'Cheque',            '📝', 0.0000, 2,  7, true),
        (p_tenant_id, 'outros',          'Outros',            '💰', 0.0000, 0,  8, true)
    ON CONFLICT (tenant_id, slug) DO NOTHING;
END;
$$;


-- ───────────────────────────────────────────────────────────────────────────
-- 12. PERMISSÕES PDV
-- ───────────────────────────────────────────────────────────────────────────

-- Adiciona permissões de PDV para admins/owners existentes
UPDATE users
SET permissoes = array_append(permissoes, 'pdv:read')
WHERE role IN ('admin','owner')
  AND NOT ('pdv:read' = ANY(permissoes));

UPDATE users
SET permissoes = array_append(permissoes, 'pdv:create')
WHERE role IN ('admin','owner')
  AND NOT ('pdv:create' = ANY(permissoes));

UPDATE users
SET permissoes = array_append(permissoes, 'pdv:update')
WHERE role IN ('admin','owner')
  AND NOT ('pdv:update' = ANY(permissoes));

UPDATE users
SET permissoes = array_append(permissoes, 'pdv:delete')
WHERE role IN ('admin','owner')
  AND NOT ('pdv:delete' = ANY(permissoes));

-- Operadores de caixa: leitura e criação
UPDATE users
SET permissoes = array_cat(permissoes, ARRAY['pdv:read','pdv:create'])
WHERE role IN ('manager','user')
  AND NOT ('pdv:read' = ANY(permissoes));


-- ───────────────────────────────────────────────────────────────────────────
-- 13. VIEW: v_pdv_resumo_caixa
--     Visão desnormalizada para o fechamento de caixa (uma linha por sessão).
-- ───────────────────────────────────────────────────────────────────────────

CREATE OR REPLACE VIEW v_pdv_resumo_caixa AS
SELECT
    c.id,
    c.tenant_id,
    c.status,
    c.aberto_em,
    c.fechado_em,
    c.saldo_abertura,
    c.saldo_sistema,
    c.saldo_informado,
    c.diferenca,

    -- Operador
    u.nome              AS operador_nome,

    -- Totais de vendas (apenas concluídas)
    COUNT(DISTINCT v.id)            AS qtd_vendas,
    COALESCE(SUM(v.total), 0)       AS total_vendas,

    -- Movimentos
    COALESCE(SUM(CASE WHEN m.tipo = 'suprimento'  THEN m.valor END), 0) AS total_suprimento,
    COALESCE(SUM(CASE WHEN m.tipo = 'sangria'     THEN m.valor END), 0) AS total_sangria,
    COALESCE(SUM(CASE WHEN m.tipo = 'reforco'     THEN m.valor END), 0) AS total_reforco,
    COALESCE(SUM(CASE WHEN m.tipo = 'despesa_pdv' THEN m.valor END), 0) AS total_despesa_pdv,

    -- Duração
    EXTRACT(EPOCH FROM (COALESCE(c.fechado_em, now()) - c.aberto_em)) / 3600 AS duracao_horas

FROM pdv_caixas c
JOIN users u ON u.id = c.operador_id
LEFT JOIN pdv_vendas   v ON v.caixa_id = c.id AND v.status = 'concluida'
LEFT JOIN pdv_movimentos m ON m.caixa_id = c.id
GROUP BY c.id, u.nome;


-- ───────────────────────────────────────────────────────────────────────────
-- 14. VIEW: v_lancamentos_completo
--     Junta lancamentos com cliente, fornecedor e origem PDV.
--     Usada no handler para evitar múltiplos JOINs repetidos.
-- ───────────────────────────────────────────────────────────────────────────

CREATE OR REPLACE VIEW v_lancamentos_completo AS
SELECT
    l.*,
    c.nome          AS cliente_nome,
    f.razao_social  AS fornecedor_nome,
    fc.nome         AS categoria_nome,
    fc.cor          AS categoria_cor,
    fc.icone        AS categoria_icone
FROM lancamentos l
LEFT JOIN clientes       c  ON c.id  = l.cliente_id    AND c.tenant_id  = l.tenant_id
LEFT JOIN fornecedores   f  ON f.id  = l.fornecedor_id AND f.tenant_id  = l.tenant_id
LEFT JOIN fin_categorias fc ON fc.slug = l.categoria   AND fc.tenant_id = l.tenant_id;

-- +goose StatementEnd


-- +goose Down
-- +goose StatementBegin

DROP VIEW  IF EXISTS v_lancamentos_completo CASCADE;
DROP VIEW  IF EXISTS v_pdv_resumo_caixa     CASCADE;

DROP FUNCTION IF EXISTS fn_seed_fin_formas_pgto  CASCADE;
DROP FUNCTION IF EXISTS fn_seed_fin_categorias   CASCADE;
DROP FUNCTION IF EXISTS fn_pdv_saldo_caixa       CASCADE;
DROP FUNCTION IF EXISTS fn_pdv_totais_caixa      CASCADE;

DROP TABLE IF EXISTS pdv_venda_pgtos   CASCADE;
DROP TABLE IF EXISTS pdv_venda_itens   CASCADE;
DROP TABLE IF EXISTS pdv_vendas        CASCADE;
DROP TABLE IF EXISTS pdv_movimentos    CASCADE;
DROP TABLE IF EXISTS pdv_caixas        CASCADE;
DROP TABLE IF EXISTS fin_formas_pgto   CASCADE;
DROP TABLE IF EXISTS fin_categorias    CASCADE;

ALTER TABLE lancamentos
    DROP COLUMN IF EXISTS origem,
    DROP COLUMN IF EXISTS origem_id,
    DROP COLUMN IF EXISTS forma_pgto,
    DROP COLUMN IF EXISTS parcelas,
    DROP COLUMN IF EXISTS caixa_id,
    DROP COLUMN IF EXISTS fornecedor_id,
    DROP COLUMN IF EXISTS cliente_id,
    DROP COLUMN IF EXISTS tags,
    DROP COLUMN IF EXISTS observacoes,
    DROP COLUMN IF EXISTS recorrente,
    DROP COLUMN IF EXISTS recorrencia;

-- +goose StatementEnd
