-- Tabel payment_allocations menyimpan hasil FIFO matching antara payment dengan
-- sub-row anak (purchase_item / marketing_delivery_product / expense_realization).
-- Setiap allocation row HARUS terhubung ke tepat 1 child via 3 nullable FK
-- (polymorphic-via-multiple-nullable-FK; lebih aman dari single polymorphic kolom).
CREATE TABLE IF NOT EXISTS payment_allocations (
    id BIGSERIAL PRIMARY KEY,
    payment_id BIGINT NOT NULL REFERENCES payments(id) ON DELETE CASCADE,
    purchase_item_id BIGINT NULL REFERENCES purchase_items(id) ON DELETE CASCADE,
    marketing_delivery_product_id BIGINT NULL REFERENCES marketing_delivery_products(id) ON DELETE CASCADE,
    expense_realization_id BIGINT NULL REFERENCES expense_realizations(id) ON DELETE CASCADE,
    amount NUMERIC(15, 3) NOT NULL CHECK (amount > 0),
    allocated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT chk_payment_alloc_exactly_one CHECK (
        num_nonnulls(purchase_item_id, marketing_delivery_product_id, expense_realization_id) = 1
    )
);

CREATE INDEX IF NOT EXISTS idx_payment_alloc_payment ON payment_allocations (payment_id);
CREATE INDEX IF NOT EXISTS idx_payment_alloc_purchase_item ON payment_allocations (purchase_item_id) WHERE purchase_item_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_payment_alloc_mdp ON payment_allocations (marketing_delivery_product_id) WHERE marketing_delivery_product_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_payment_alloc_realization ON payment_allocations (expense_realization_id) WHERE expense_realization_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_payment_alloc_allocated_at ON payment_allocations (allocated_at);

-- Helper partial indexes untuk FIFO loop performance
CREATE INDEX IF NOT EXISTS idx_purchase_items_received_date_partial ON purchase_items (received_date) WHERE received_date IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_mdp_delivery_date_partial ON marketing_delivery_products (delivery_date) WHERE delivery_date IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_payments_party_active ON payments (party_type, party_id, payment_date) WHERE deleted_at IS NULL;
