-- Migration 011: User-level referral codes + personal circle + points system
-- Extends the existing tenant-level referral system (006) to support
-- individual user-to-user referrals and a unified points economy.
--
-- Design:
--   • Each user gets their own referral code (vs. per-tenant in 006)
--   • Referral relationships track user→user (personal circle, max 2 levels)
--   • Points replace raw USD credits as the reward currency (flexible redemption)
--   • Points ledger is append-only; balance is a denormalized cache

-- ── 1. User referral codes ──────────────────────────────────────────────────
-- One row per user. Created automatically on first registration.
CREATE TABLE IF NOT EXISTS public.user_referral_codes (
    user_id         UUID        PRIMARY KEY,
    code            VARCHAR(20) NOT NULL UNIQUE,
    click_count     INT         NOT NULL DEFAULT 0,
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- ── 2. User referral relationships (personal circle) ────────────────────────
-- Tracks who invited whom at the user level.
-- Each user can be referred at most once (UNIQUE referred_user_id).
-- level: 1 = direct invite, 2 = indirect (friend of friend).
-- status: PENDING → ACTIVE (first engagement) → REWARDED (first payment done)
--         EXPIRED (never activated after 90 days)
CREATE TABLE IF NOT EXISTS public.user_referral_relationships (
    id                  UUID        PRIMARY KEY DEFAULT gen_random_uuid(),
    referrer_user_id    UUID        NOT NULL,
    referred_user_id    UUID        NOT NULL UNIQUE,
    referral_code       VARCHAR(20) NOT NULL,
    level               SMALLINT    NOT NULL DEFAULT 1 CHECK (level IN (1, 2)),
    status              VARCHAR(20) NOT NULL DEFAULT 'PENDING'
                            CHECK (status IN ('PENDING','ACTIVE','REWARDED','EXPIRED')),
    activated_at        TIMESTAMPTZ,
    rewarded_at         TIMESTAMPTZ,
    created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_urr_referrer  ON public.user_referral_relationships(referrer_user_id);
CREATE INDEX IF NOT EXISTS idx_urr_status    ON public.user_referral_relationships(status);
CREATE INDEX IF NOT EXISTS idx_urr_created   ON public.user_referral_relationships(created_at);

-- ── 3. Points ledger (append-only) ──────────────────────────────────────────
-- Every point event is a row.  delta > 0 = earned, delta < 0 = spent.
-- type values:
--   REFERRAL_FIRST_PAYMENT  – first subscription payment by referred user
--   REFERRAL_RECURRING      – recurring monthly payment reward (≤12 months)
--   REFERRAL_L2             – level-2 indirect reward (≤6 months)
--   REFERRAL_WELCOME        – welcome bonus awarded to newly referred user
--   REDEMPTION_QUOTA        – redeemed for extra usage quota
--   REDEMPTION_UNLOCK       – redeemed to unlock a premium agent
--   ADMIN_GRANT             – platform admin manual grant/deduction
--   EXPIRY                  – points expiry deduction
CREATE TABLE IF NOT EXISTS public.user_point_transactions (
    id          UUID        PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id     UUID        NOT NULL,
    delta       INT         NOT NULL,
    type        VARCHAR(40) NOT NULL,
    ref_id      UUID,           -- FK to user_referral_relationships.id or redemption id
    note        TEXT,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_upt_user_id   ON public.user_point_transactions(user_id);
CREATE INDEX IF NOT EXISTS idx_upt_created   ON public.user_point_transactions(created_at);
CREATE INDEX IF NOT EXISTS idx_upt_ref_id    ON public.user_point_transactions(ref_id);

-- ── 4. Points balance (denormalized cache) ───────────────────────────────────
-- Maintained atomically alongside user_point_transactions.
-- balance = total_earned + total_spent  (total_spent is always ≤ 0, so balance = earned - |spent|)
CREATE TABLE IF NOT EXISTS public.user_point_balances (
    user_id         UUID    PRIMARY KEY,
    balance         INT     NOT NULL DEFAULT 0,
    total_earned    INT     NOT NULL DEFAULT 0,
    total_spent     INT     NOT NULL DEFAULT 0,
    updated_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
