-- ============================================================================
-- SCHEMA: users
-- TABLE: risk_profiles
-- DESCRIPTION: Perfil de riesgo del usuario para trading
-- VERSION: 1.0.0
-- CREATED: 2026-01-16
-- SPRINT: Sprint 1 - DDL Implementation Roadmap Q1-2026
-- ============================================================================

-- Enum para perfil de riesgo
DO $$ BEGIN
    CREATE TYPE users.risk_tolerance AS ENUM (
        'conservative',     -- Bajo riesgo, preservacion de capital
        'moderate',         -- Riesgo moderado, balance crecimiento/seguridad
        'aggressive',       -- Alto riesgo, maximizar retornos
        'speculative'       -- Muy alto riesgo, trading activo
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Enum para experiencia de trading
DO $$ BEGIN
    CREATE TYPE users.trading_experience AS ENUM (
        'none',             -- Sin experiencia
        'beginner',         -- Menos de 1 año
        'intermediate',     -- 1-3 años
        'advanced',         -- 3-5 años
        'expert'            -- 5+ años
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Tabla de Perfiles de Riesgo
CREATE TABLE IF NOT EXISTS users.risk_profiles (
    -- Identificadores
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL UNIQUE REFERENCES users.users(id) ON DELETE CASCADE,
    tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,

    -- Perfil de riesgo
    risk_tolerance users.risk_tolerance NOT NULL DEFAULT 'moderate',
    trading_experience users.trading_experience NOT NULL DEFAULT 'none',

    -- Cuestionario de adecuacion (suitability)
    questionnaire_completed BOOLEAN NOT NULL DEFAULT FALSE,
    questionnaire_completed_at TIMESTAMPTZ,
    questionnaire_version VARCHAR(20),
    questionnaire_responses JSONB,
    questionnaire_score INTEGER CHECK (questionnaire_score BETWEEN 0 AND 100),

    -- Objetivos de inversion
    investment_objectives JSONB DEFAULT '{
        "primary_goal": "growth",
        "time_horizon": "medium_term",
        "liquidity_needs": "moderate"
    }'::JSONB,

    -- Situacion financiera
    financial_situation JSONB DEFAULT '{
        "net_worth_range": "not_specified",
        "annual_income_range": "not_specified",
        "liquid_assets_range": "not_specified",
        "investable_amount_range": "not_specified"
    }'::JSONB,

    -- Conocimiento de productos
    product_knowledge JSONB DEFAULT '{
        "forex": "none",
        "stocks": "none",
        "options": "none",
        "futures": "none",
        "crypto": "none",
        "leverage_products": "none"
    }'::JSONB,

    -- Historial de trading declarado
    trading_history JSONB DEFAULT '{
        "years_trading": 0,
        "average_trades_per_month": 0,
        "largest_single_trade": 0,
        "has_professional_experience": false
    }'::JSONB,

    -- Limites basados en perfil
    max_position_size_percent DECIMAL(5, 2) NOT NULL DEFAULT 5.00,       -- % del capital por posicion
    max_daily_loss_percent DECIMAL(5, 2) NOT NULL DEFAULT 3.00,          -- % perdida diaria maxima
    max_total_exposure_percent DECIMAL(5, 2) NOT NULL DEFAULT 50.00,     -- % exposicion total
    max_leverage INTEGER NOT NULL DEFAULT 10,
    allowed_instruments JSONB DEFAULT '["forex_majors", "indices"]'::JSONB,

    -- Score de riesgo calculado
    calculated_risk_score INTEGER CHECK (calculated_risk_score BETWEEN 1 AND 10),
    risk_score_factors JSONB,
    last_risk_assessment TIMESTAMPTZ,

    -- Warnings y restricciones
    risk_warnings_acknowledged JSONB DEFAULT '[]'::JSONB,
    trading_restrictions JSONB DEFAULT '[]'::JSONB,
    requires_additional_disclosure BOOLEAN NOT NULL DEFAULT FALSE,

    -- Clasificacion regulatoria
    regulatory_classification VARCHAR(50) DEFAULT 'retail',  -- 'retail', 'professional', 'eligible_counterparty'
    classification_request_status VARCHAR(50),
    classification_approved_at TIMESTAMPTZ,

    -- Metadata
    metadata JSONB DEFAULT '{}'::JSONB,

    -- Timestamps
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

COMMENT ON TABLE users.risk_profiles IS
'Perfil de riesgo del usuario basado en cuestionario de adecuacion';

COMMENT ON COLUMN users.risk_profiles.risk_tolerance IS
'Tolerancia al riesgo declarada: conservative, moderate, aggressive, speculative';

COMMENT ON COLUMN users.risk_profiles.calculated_risk_score IS
'Score de riesgo calculado (1-10), donde 10 es maximo riesgo permitido';

COMMENT ON COLUMN users.risk_profiles.regulatory_classification IS
'Clasificacion segun MiFID II: retail, professional, eligible_counterparty';

-- Indices
CREATE INDEX IF NOT EXISTS idx_risk_profiles_user_id
    ON users.risk_profiles(user_id);

CREATE INDEX IF NOT EXISTS idx_risk_profiles_tenant_id
    ON users.risk_profiles(tenant_id);

CREATE INDEX IF NOT EXISTS idx_risk_profiles_tolerance
    ON users.risk_profiles(risk_tolerance);

CREATE INDEX IF NOT EXISTS idx_risk_profiles_experience
    ON users.risk_profiles(trading_experience);

CREATE INDEX IF NOT EXISTS idx_risk_profiles_classification
    ON users.risk_profiles(regulatory_classification);

CREATE INDEX IF NOT EXISTS idx_risk_profiles_pending_questionnaire
    ON users.risk_profiles(tenant_id, created_at)
    WHERE questionnaire_completed = FALSE;

-- GIN index para busquedas en JSONB
CREATE INDEX IF NOT EXISTS idx_risk_profiles_knowledge_gin
    ON users.risk_profiles USING GIN (product_knowledge);

-- Trigger para updated_at
DROP TRIGGER IF EXISTS risk_profile_updated_at ON users.risk_profiles;
CREATE TRIGGER risk_profile_updated_at
    BEFORE UPDATE ON users.risk_profiles
    FOR EACH ROW
    EXECUTE FUNCTION users.update_user_timestamp();

-- Funcion para calcular risk score automaticamente
CREATE OR REPLACE FUNCTION users.calculate_risk_score()
RETURNS TRIGGER AS $$
DECLARE
    v_score INTEGER := 5;  -- Base score
    v_experience_weight INTEGER;
    v_tolerance_weight INTEGER;
BEGIN
    -- Ajustar por experiencia
    CASE NEW.trading_experience
        WHEN 'none' THEN v_experience_weight := -2;
        WHEN 'beginner' THEN v_experience_weight := -1;
        WHEN 'intermediate' THEN v_experience_weight := 0;
        WHEN 'advanced' THEN v_experience_weight := 1;
        WHEN 'expert' THEN v_experience_weight := 2;
        ELSE v_experience_weight := 0;
    END CASE;

    -- Ajustar por tolerancia al riesgo
    CASE NEW.risk_tolerance
        WHEN 'conservative' THEN v_tolerance_weight := -2;
        WHEN 'moderate' THEN v_tolerance_weight := 0;
        WHEN 'aggressive' THEN v_tolerance_weight := 2;
        WHEN 'speculative' THEN v_tolerance_weight := 3;
        ELSE v_tolerance_weight := 0;
    END CASE;

    -- Calcular score final
    v_score := v_score + v_experience_weight + v_tolerance_weight;

    -- Asegurar rango 1-10
    v_score := GREATEST(1, LEAST(10, v_score));

    NEW.calculated_risk_score := v_score;
    NEW.last_risk_assessment := NOW();

    -- Guardar factores del calculo
    NEW.risk_score_factors := jsonb_build_object(
        'base_score', 5,
        'experience_weight', v_experience_weight,
        'tolerance_weight', v_tolerance_weight,
        'final_score', v_score
    );

    -- Ajustar limites basados en score
    IF v_score <= 3 THEN
        NEW.max_leverage := 5;
        NEW.max_position_size_percent := 2.00;
        NEW.max_daily_loss_percent := 1.00;
    ELSIF v_score <= 5 THEN
        NEW.max_leverage := 10;
        NEW.max_position_size_percent := 5.00;
        NEW.max_daily_loss_percent := 3.00;
    ELSIF v_score <= 7 THEN
        NEW.max_leverage := 20;
        NEW.max_position_size_percent := 10.00;
        NEW.max_daily_loss_percent := 5.00;
    ELSE
        NEW.max_leverage := 50;
        NEW.max_position_size_percent := 15.00;
        NEW.max_daily_loss_percent := 10.00;
    END IF;

    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS risk_score_calc ON users.risk_profiles;
CREATE TRIGGER risk_score_calc
    BEFORE INSERT OR UPDATE OF risk_tolerance, trading_experience ON users.risk_profiles
    FOR EACH ROW
    EXECUTE FUNCTION users.calculate_risk_score();

-- RLS Policy para multi-tenancy
ALTER TABLE users.risk_profiles ENABLE ROW LEVEL SECURITY;

CREATE POLICY risk_profiles_tenant_isolation ON users.risk_profiles
    FOR ALL
    USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);

-- Grants
GRANT SELECT, INSERT, UPDATE ON users.risk_profiles TO trading_app;
GRANT SELECT ON users.risk_profiles TO trading_readonly;
