-- ============================================================
-- Migration 011: Capital Ledger Hardening
-- Date: 2026-02-16
-- Purpose: Introduce deterministic per-profile capital ledger and helper RPCs.
-- ============================================================

CREATE TABLE IF NOT EXISTS capital_ledgers (
    profile_id uuid PRIMARY KEY REFERENCES trade_profiles(id) ON DELETE CASCADE,
    allocated_capital numeric NOT NULL DEFAULT 0,
    reserved_for_orders numeric NOT NULL DEFAULT 0,
    reserved_for_positions numeric NOT NULL DEFAULT 0,
    realized_pnl numeric NOT NULL DEFAULT 0,
    updated_at timestamptz NOT NULL DEFAULT now()
);

COMMENT ON TABLE capital_ledgers IS 'Deterministic ledger for profile capital isolation.';
COMMENT ON COLUMN capital_ledgers.realized_pnl IS 'Cumulative realized profit/loss for the profile.';

CREATE INDEX IF NOT EXISTS idx_capital_ledgers_profile ON capital_ledgers(profile_id);

ALTER TABLE capital_ledgers ENABLE ROW LEVEL SECURITY;

DROP POLICY IF EXISTS "Users can manage own ledger" ON capital_ledgers;
CREATE POLICY "Users can manage own ledger" ON capital_ledgers
    FOR ALL
    USING (auth.uid() = (SELECT user_id FROM trade_profiles WHERE id = capital_ledgers.profile_id))
    WITH CHECK (auth.uid() = (SELECT user_id FROM trade_profiles WHERE id = capital_ledgers.profile_id));

CREATE OR REPLACE FUNCTION fn_reserve_for_order(p_profile uuid, p_amount numeric)
RETURNS capital_ledgers AS $$
DECLARE
    ledger capital_ledgers;
BEGIN
    UPDATE capital_ledgers
    SET reserved_for_orders = reserved_for_orders + p_amount,
        updated_at = now()
    WHERE profile_id = p_profile
      AND (allocated_capital - reserved_for_orders - reserved_for_positions) >= p_amount
    RETURNING * INTO ledger;

    IF NOT FOUND THEN
        RAISE EXCEPTION 'Insufficient capital for profile %', p_profile;
    END IF;

    RETURN ledger;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

CREATE OR REPLACE FUNCTION fn_release_order_reservation(p_profile uuid, p_amount numeric)
RETURNS capital_ledgers AS $$
DECLARE
    ledger capital_ledgers;
BEGIN
    UPDATE capital_ledgers
    SET reserved_for_orders = GREATEST(reserved_for_orders - p_amount, 0),
        updated_at = now()
    WHERE profile_id = p_profile
    RETURNING * INTO ledger;

    RETURN ledger;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

CREATE OR REPLACE FUNCTION fn_adjust_position_reservation(p_profile uuid, p_delta numeric)
RETURNS capital_ledgers AS $$
DECLARE
    ledger capital_ledgers;
BEGIN
    UPDATE capital_ledgers
    SET reserved_for_positions = GREATEST(reserved_for_positions + p_delta, 0),
        updated_at = now()
    WHERE profile_id = p_profile
    RETURNING * INTO ledger;

    RETURN ledger;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

CREATE OR REPLACE FUNCTION fn_record_realized_pnl(p_profile uuid, p_delta numeric)
RETURNS capital_ledgers AS $$
DECLARE
    ledger capital_ledgers;
BEGIN
    UPDATE capital_ledgers
    SET realized_pnl = realized_pnl + COALESCE(p_delta, 0),
        updated_at = now()
    WHERE profile_id = p_profile
    RETURNING * INTO ledger;

    RETURN ledger;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

CREATE OR REPLACE FUNCTION fn_rebuild_ledger(p_profile uuid, p_reserved_orders numeric, p_reserved_positions numeric)
RETURNS capital_ledgers AS $$
DECLARE
    ledger capital_ledgers;
BEGIN
    INSERT INTO capital_ledgers (profile_id, allocated_capital, reserved_for_orders, reserved_for_positions, updated_at)
    VALUES (p_profile, (SELECT allocated_capital FROM trade_profiles WHERE id = p_profile), p_reserved_orders, p_reserved_positions, now())
    ON CONFLICT (profile_id) DO UPDATE
      SET reserved_for_orders = p_reserved_orders,
          reserved_for_positions = p_reserved_positions,
          updated_at = now()
    RETURNING * INTO ledger;

    RETURN ledger;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
