-- ============================================================================
-- OrbiQuant IA - Esquema FINANCIAL
-- ============================================================================
-- Archivo: 05_financial_schema.sql
-- Descripción: Pagos, suscripciones, wallets y transacciones
-- Fecha: 2025-12-05
-- ============================================================================

SET search_path TO financial;

-- ============================================================================
-- TIPOS ENUMERADOS
-- ============================================================================

CREATE TYPE subscription_status_enum AS ENUM (
    'trialing',      -- Período de prueba
    'active',        -- Activa y pagando
    'past_due',      -- Pago vencido
    'cancelled',     -- Cancelada
    'unpaid',        -- Sin pago
    'paused'         -- Pausada
);

CREATE TYPE payment_status_enum AS ENUM (
    'pending',
    'processing',
    'succeeded',
    'failed',
    'refunded',
    'cancelled'
);

CREATE TYPE payment_method_enum AS ENUM (
    'card',
    'bank_transfer',
    'paypal',
    'crypto',
    'wallet_balance'
);

-- ============================================================================
-- TABLA: subscription_plans
-- Descripción: Planes de suscripción disponibles
-- ============================================================================
CREATE TABLE IF NOT EXISTS subscription_plans (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),

    -- Identificación
    name VARCHAR(50) NOT NULL,
    slug VARCHAR(50) NOT NULL UNIQUE,
    description TEXT,

    -- Pricing
    price_monthly DECIMAL(10,2) NOT NULL,
    price_yearly DECIMAL(10,2),
    currency CHAR(3) DEFAULT 'USD',

    -- Stripe
    stripe_price_id_monthly VARCHAR(100),
    stripe_price_id_yearly VARCHAR(100),
    stripe_product_id VARCHAR(100),

    -- Features (JSON array)
    features JSONB DEFAULT '[]', -- [{name, description, included: boolean}]

    -- Límites
    max_watchlists INT,
    max_alerts INT,
    ml_predictions_access BOOLEAN DEFAULT FALSE,
    signals_access BOOLEAN DEFAULT FALSE,
    backtesting_access BOOLEAN DEFAULT FALSE,
    api_access BOOLEAN DEFAULT FALSE,
    priority_support BOOLEAN DEFAULT FALSE,

    -- Educación
    courses_access VARCHAR(20) DEFAULT 'none', -- 'none', 'free_only', 'basic', 'all'

    -- Orden de display
    sort_order INT DEFAULT 0,
    is_featured BOOLEAN DEFAULT FALSE,

    -- Estado
    is_active BOOLEAN DEFAULT TRUE,

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_plans_slug ON subscription_plans(slug);

-- ============================================================================
-- TABLA: stripe_customers
-- Descripción: Clientes de Stripe vinculados a usuarios
-- ============================================================================
CREATE TABLE IF NOT EXISTS stripe_customers (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    user_id UUID NOT NULL UNIQUE REFERENCES auth.users(id) ON DELETE CASCADE,

    stripe_customer_id VARCHAR(100) NOT NULL UNIQUE,
    email VARCHAR(255),

    -- Método de pago por defecto
    default_payment_method_id VARCHAR(100),

    -- Metadata
    metadata JSONB,

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_stripe_customers_user ON stripe_customers(user_id);
CREATE INDEX idx_stripe_customers_stripe ON stripe_customers(stripe_customer_id);

-- ============================================================================
-- TABLA: subscriptions
-- Descripción: Suscripciones activas de usuarios
-- ============================================================================
CREATE TABLE IF NOT EXISTS subscriptions (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE RESTRICT,
    plan_id UUID NOT NULL REFERENCES subscription_plans(id),

    -- Stripe
    stripe_subscription_id VARCHAR(100) UNIQUE,
    stripe_customer_id VARCHAR(100) REFERENCES stripe_customers(stripe_customer_id),

    -- Estado
    status subscription_status_enum DEFAULT 'active',

    -- Período de facturación
    billing_cycle VARCHAR(20) DEFAULT 'monthly', -- 'monthly', 'yearly'
    current_period_start TIMESTAMPTZ,
    current_period_end TIMESTAMPTZ,

    -- Trial
    trial_start TIMESTAMPTZ,
    trial_end TIMESTAMPTZ,

    -- Cancelación
    cancel_at_period_end BOOLEAN DEFAULT FALSE,
    cancelled_at TIMESTAMPTZ,
    cancellation_reason TEXT,

    -- Precio actual (puede diferir del plan por descuentos)
    current_price DECIMAL(10,2),
    currency CHAR(3) DEFAULT 'USD',

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_subscriptions_user ON subscriptions(user_id);
CREATE INDEX idx_subscriptions_plan ON subscriptions(plan_id);
CREATE INDEX idx_subscriptions_status ON subscriptions(status);
CREATE INDEX idx_subscriptions_stripe ON subscriptions(stripe_subscription_id);

-- ============================================================================
-- TABLA: wallets
-- Descripción: Wallets internos de usuarios
-- ============================================================================
CREATE TABLE IF NOT EXISTS wallets (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE RESTRICT,

    -- Balance
    currency CHAR(3) NOT NULL DEFAULT 'USD',
    balance DECIMAL(15,2) NOT NULL DEFAULT 0,
    available_balance DECIMAL(15,2) NOT NULL DEFAULT 0,
    pending_balance DECIMAL(15,2) NOT NULL DEFAULT 0,

    -- Estado
    is_active BOOLEAN DEFAULT TRUE,

    -- Límites
    daily_withdrawal_limit DECIMAL(15,2) DEFAULT 10000,
    monthly_withdrawal_limit DECIMAL(15,2) DEFAULT 50000,

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,

    UNIQUE(user_id, currency)
);

CREATE INDEX idx_wallets_user ON wallets(user_id);

-- ============================================================================
-- TABLA: wallet_transactions
-- Descripción: Transacciones en wallets
-- ============================================================================
CREATE TABLE IF NOT EXISTS wallet_transactions (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    wallet_id UUID NOT NULL REFERENCES wallets(id) ON DELETE RESTRICT,
    user_id UUID NOT NULL REFERENCES auth.users(id),

    -- Tipo y monto
    transaction_type public.transaction_type_enum NOT NULL,
    amount DECIMAL(15,2) NOT NULL,
    currency CHAR(3) DEFAULT 'USD',

    -- Balance
    balance_before DECIMAL(15,2) NOT NULL,
    balance_after DECIMAL(15,2) NOT NULL,

    -- Referencia
    reference_type VARCHAR(50), -- 'payment', 'subscription', 'investment_account', 'refund'
    reference_id UUID,
    external_reference VARCHAR(100), -- ID externo (Stripe, etc.)

    -- Descripción
    description TEXT,

    -- Estado
    status payment_status_enum DEFAULT 'succeeded',

    -- Metadata
    metadata JSONB,

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_wallet_tx_wallet ON wallet_transactions(wallet_id);
CREATE INDEX idx_wallet_tx_user ON wallet_transactions(user_id);
CREATE INDEX idx_wallet_tx_type ON wallet_transactions(transaction_type);
CREATE INDEX idx_wallet_tx_created ON wallet_transactions(created_at DESC);

-- ============================================================================
-- TABLA: payments
-- Descripción: Pagos procesados
-- ============================================================================
CREATE TABLE IF NOT EXISTS payments (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    user_id UUID NOT NULL REFERENCES auth.users(id),

    -- Tipo
    payment_type VARCHAR(50) NOT NULL, -- 'subscription', 'course', 'deposit', 'one_time'

    -- Monto
    amount DECIMAL(10,2) NOT NULL,
    currency CHAR(3) DEFAULT 'USD',
    fee DECIMAL(10,2) DEFAULT 0,
    net_amount DECIMAL(10,2),

    -- Método
    payment_method payment_method_enum,
    payment_method_details JSONB, -- Últimos 4 dígitos, tipo de tarjeta, etc.

    -- Stripe
    stripe_payment_intent_id VARCHAR(100),
    stripe_charge_id VARCHAR(100),
    stripe_invoice_id VARCHAR(100),

    -- Estado
    status payment_status_enum DEFAULT 'pending',
    failure_reason TEXT,

    -- Referencia
    reference_type VARCHAR(50), -- 'subscription', 'course', 'wallet_deposit'
    reference_id UUID,

    -- Descripción
    description TEXT,

    -- Metadata
    metadata JSONB,
    ip_address INET,

    -- Facturación
    invoice_url TEXT,
    receipt_url TEXT,

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_payments_user ON payments(user_id);
CREATE INDEX idx_payments_status ON payments(status);
CREATE INDEX idx_payments_type ON payments(payment_type);
CREATE INDEX idx_payments_stripe ON payments(stripe_payment_intent_id);
CREATE INDEX idx_payments_created ON payments(created_at DESC);

-- ============================================================================
-- TABLA: refunds
-- Descripción: Reembolsos procesados
-- ============================================================================
CREATE TABLE IF NOT EXISTS refunds (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    payment_id UUID NOT NULL REFERENCES payments(id),
    user_id UUID NOT NULL REFERENCES auth.users(id),

    -- Monto
    amount DECIMAL(10,2) NOT NULL,
    currency CHAR(3) DEFAULT 'USD',

    -- Stripe
    stripe_refund_id VARCHAR(100),

    -- Razón
    reason VARCHAR(100),
    notes TEXT,

    -- Estado
    status payment_status_enum DEFAULT 'pending',

    -- Procesado por
    processed_by UUID REFERENCES auth.users(id),

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_refunds_payment ON refunds(payment_id);
CREATE INDEX idx_refunds_user ON refunds(user_id);

-- ============================================================================
-- TABLA: invoices
-- Descripción: Facturas generadas
-- ============================================================================
CREATE TABLE IF NOT EXISTS invoices (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    user_id UUID NOT NULL REFERENCES auth.users(id),

    -- Número de factura
    invoice_number VARCHAR(50) NOT NULL UNIQUE,

    -- Stripe
    stripe_invoice_id VARCHAR(100) UNIQUE,

    -- Montos
    subtotal DECIMAL(10,2) NOT NULL,
    tax DECIMAL(10,2) DEFAULT 0,
    total DECIMAL(10,2) NOT NULL,
    amount_paid DECIMAL(10,2) DEFAULT 0,
    amount_due DECIMAL(10,2),
    currency CHAR(3) DEFAULT 'USD',

    -- Estado
    status VARCHAR(20) DEFAULT 'draft', -- 'draft', 'open', 'paid', 'void', 'uncollectible'

    -- Fechas
    due_date DATE,
    paid_at TIMESTAMPTZ,

    -- Items
    line_items JSONB DEFAULT '[]', -- [{description, quantity, unit_price, amount}]

    -- PDFs
    pdf_url TEXT,
    hosted_invoice_url TEXT,

    -- Datos fiscales del cliente
    billing_details JSONB,

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_invoices_user ON invoices(user_id);
CREATE INDEX idx_invoices_status ON invoices(status);
CREATE INDEX idx_invoices_number ON invoices(invoice_number);

-- ============================================================================
-- TABLA: payout_requests
-- Descripción: Solicitudes de retiro a cuenta bancaria/externa
-- ============================================================================
CREATE TABLE IF NOT EXISTS payout_requests (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    user_id UUID NOT NULL REFERENCES auth.users(id),
    wallet_id UUID NOT NULL REFERENCES wallets(id),

    -- Monto
    amount DECIMAL(15,2) NOT NULL,
    currency CHAR(3) DEFAULT 'USD',
    fee DECIMAL(10,2) DEFAULT 0,
    net_amount DECIMAL(15,2),

    -- Destino
    payout_method VARCHAR(50) NOT NULL, -- 'bank_transfer', 'paypal', 'crypto'
    destination_details JSONB, -- Cuenta bancaria, dirección, etc.

    -- Estado
    status VARCHAR(20) DEFAULT 'pending', -- 'pending', 'processing', 'completed', 'rejected', 'cancelled'
    processed_at TIMESTAMPTZ,
    completed_at TIMESTAMPTZ,

    -- Procesamiento
    processed_by UUID REFERENCES auth.users(id),
    rejection_reason TEXT,
    external_reference VARCHAR(100),

    -- Transacción de wallet
    wallet_transaction_id UUID REFERENCES wallet_transactions(id),

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_payouts_user ON payout_requests(user_id);
CREATE INDEX idx_payouts_wallet ON payout_requests(wallet_id);
CREATE INDEX idx_payouts_status ON payout_requests(status);

-- ============================================================================
-- TABLA: promo_codes
-- Descripción: Códigos promocionales y descuentos
-- ============================================================================
CREATE TABLE IF NOT EXISTS promo_codes (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),

    code VARCHAR(50) NOT NULL UNIQUE,
    description TEXT,

    -- Tipo de descuento
    discount_type VARCHAR(20) NOT NULL, -- 'percentage', 'fixed_amount'
    discount_value DECIMAL(10,2) NOT NULL,
    currency CHAR(3) DEFAULT 'USD',

    -- Aplicabilidad
    applies_to VARCHAR(50) DEFAULT 'all', -- 'all', 'subscription', 'course'
    applicable_plan_ids UUID[],
    applicable_course_ids UUID[],

    -- Límites
    max_uses INT,
    current_uses INT DEFAULT 0,
    max_uses_per_user INT DEFAULT 1,

    -- Validez
    valid_from TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    valid_until TIMESTAMPTZ,

    -- Requisitos
    min_purchase_amount DECIMAL(10,2),
    first_time_only BOOLEAN DEFAULT FALSE,

    -- Estado
    is_active BOOLEAN DEFAULT TRUE,

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_promo_codes_code ON promo_codes(code);
CREATE INDEX idx_promo_codes_active ON promo_codes(is_active) WHERE is_active = TRUE;

-- ============================================================================
-- TABLA: promo_code_uses
-- Descripción: Uso de códigos promocionales
-- ============================================================================
CREATE TABLE IF NOT EXISTS promo_code_uses (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    promo_code_id UUID NOT NULL REFERENCES promo_codes(id),
    user_id UUID NOT NULL REFERENCES auth.users(id),
    payment_id UUID REFERENCES payments(id),

    discount_applied DECIMAL(10,2) NOT NULL,

    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_promo_uses_code ON promo_code_uses(promo_code_id);
CREATE INDEX idx_promo_uses_user ON promo_code_uses(user_id);

-- ============================================================================
-- TRIGGERS
-- ============================================================================

CREATE TRIGGER update_plans_updated_at
    BEFORE UPDATE ON subscription_plans
    FOR EACH ROW
    EXECUTE FUNCTION public.update_updated_at_column();

CREATE TRIGGER update_stripe_customers_updated_at
    BEFORE UPDATE ON stripe_customers
    FOR EACH ROW
    EXECUTE FUNCTION public.update_updated_at_column();

CREATE TRIGGER update_subscriptions_updated_at
    BEFORE UPDATE ON subscriptions
    FOR EACH ROW
    EXECUTE FUNCTION public.update_updated_at_column();

CREATE TRIGGER update_wallets_updated_at
    BEFORE UPDATE ON wallets
    FOR EACH ROW
    EXECUTE FUNCTION public.update_updated_at_column();

CREATE TRIGGER update_payments_updated_at
    BEFORE UPDATE ON payments
    FOR EACH ROW
    EXECUTE FUNCTION public.update_updated_at_column();

CREATE TRIGGER update_invoices_updated_at
    BEFORE UPDATE ON invoices
    FOR EACH ROW
    EXECUTE FUNCTION public.update_updated_at_column();

CREATE TRIGGER update_payouts_updated_at
    BEFORE UPDATE ON payout_requests
    FOR EACH ROW
    EXECUTE FUNCTION public.update_updated_at_column();
