-- Migration 978: Refund state machine for Hyperswitch reverse-charge (v1.0.6)
-- Before v1.0.6, RefundOrder marked orders as `refunded` immediately after
-- POSTing to /refunds — treating Hyperswitch's synchronous API ack as
-- confirmation that the money had moved. In reality the PSP returns `pending`
-- and only confirms via webhook (`refund_succeeded` / `refund_failed`).
-- Customers could see "refunded" in the UI while their bank account still
-- hadn't been credited.
--
-- This migration introduces an auditable refund row that tracks the full
-- lifecycle: pending → (succeeded | failed). Uniqueness on
-- hyperswitch_refund_id is the load-bearing constraint — it guarantees that
-- the webhook handler can safely retry (idempotent 200) because a duplicate
-- PSP notification lands on the same DB row.

CREATE TABLE IF NOT EXISTS public.refunds (
    id                     UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    order_id               UUID NOT NULL REFERENCES public.orders(id) ON DELETE CASCADE,
    initiator_id           UUID NOT NULL REFERENCES public.users(id) ON DELETE SET NULL,
    hyperswitch_payment_id TEXT NOT NULL,
    hyperswitch_refund_id  TEXT UNIQUE,
    amount_cents           BIGINT NOT NULL,
    currency               VARCHAR(3) NOT NULL DEFAULT 'EUR',
    reason                 TEXT NOT NULL DEFAULT '',
    status                 TEXT NOT NULL DEFAULT 'pending',
    error_message          TEXT,
    succeeded_at           TIMESTAMPTZ,
    failed_at              TIMESTAMPTZ,
    created_at             TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at             TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_refunds_order_id ON public.refunds(order_id);
CREATE INDEX IF NOT EXISTS idx_refunds_status ON public.refunds(status);
CREATE INDEX IF NOT EXISTS idx_refunds_hyperswitch_payment_id
    ON public.refunds(hyperswitch_payment_id);
