-- ============================================================================
-- SCHEMA: ml
-- TABLE: market_analysis
-- DESCRIPTION: Analisis de mercado generado por ML (sesgo, volatilidad, estructura)
-- VERSION: 1.0.0
-- CREATED: 2026-01-16
-- SPRINT: Sprint 4 - DDL Implementation Roadmap Q1-2026
-- ============================================================================

-- Enum para tipo de analisis
DO $$ BEGIN
    CREATE TYPE ml.analysis_type AS ENUM (
        'daily_bias',           -- Sesgo diario
        'weekly_outlook',       -- Perspectiva semanal
        'session_analysis',     -- Analisis de sesion
        'structure_analysis',   -- Analisis de estructura
        'volatility_forecast',  -- Pronostico de volatilidad
        'correlation_report',   -- Reporte de correlaciones
        'sentiment_analysis',   -- Analisis de sentimiento
        'fundamental_impact',   -- Impacto fundamental
        'comprehensive'         -- Analisis completo
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Enum para sesgo de mercado
DO $$ BEGIN
    CREATE TYPE ml.market_bias AS ENUM (
        'strong_bullish',       -- Fuertemente alcista
        'bullish',              -- Alcista
        'slightly_bullish',     -- Ligeramente alcista
        'neutral',              -- Neutral
        'slightly_bearish',     -- Ligeramente bajista
        'bearish',              -- Bajista
        'strong_bearish'        -- Fuertemente bajista
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Enum para regimen de volatilidad
DO $$ BEGIN
    CREATE TYPE ml.volatility_regime AS ENUM (
        'extremely_low',        -- Extremadamente baja
        'low',                  -- Baja
        'normal',               -- Normal
        'high',                 -- Alta
        'extreme',              -- Extrema
        'transitioning'         -- En transicion
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Enum para estructura de mercado
DO $$ BEGIN
    CREATE TYPE ml.market_structure AS ENUM (
        'uptrend_strong',       -- Tendencia alcista fuerte
        'uptrend_weak',         -- Tendencia alcista debil
        'downtrend_strong',     -- Tendencia bajista fuerte
        'downtrend_weak',       -- Tendencia bajista debil
        'ranging_tight',        -- Rango estrecho
        'ranging_wide',         -- Rango amplio
        'consolidating',        -- Consolidando
        'breaking_out',         -- Rompiendo
        'reversing'             -- Revirtiendo
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Tabla de Analisis de Mercado
CREATE TABLE IF NOT EXISTS ml.market_analysis (
    -- Identificadores
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL,

    -- Simbolo y scope
    symbol VARCHAR(20) NOT NULL,
    asset_class ml.asset_class NOT NULL DEFAULT 'FOREX',
    analysis_type ml.analysis_type NOT NULL,
    timeframe VARCHAR(10) NOT NULL DEFAULT 'D1',

    -- Periodo del analisis
    analysis_date DATE NOT NULL,
    valid_from TIMESTAMPTZ NOT NULL,
    valid_until TIMESTAMPTZ NOT NULL,

    -- Sesgo y direccion
    bias ml.market_bias NOT NULL,
    bias_confidence DECIMAL(5, 4) NOT NULL DEFAULT 0.5
        CHECK (bias_confidence BETWEEN 0 AND 1),
    bias_reasoning TEXT,

    -- Estructura de mercado
    structure ml.market_structure NOT NULL,
    structure_timeframe VARCHAR(10),                    -- TF de la estructura dominante
    trend_strength DECIMAL(5, 2),                       -- -100 a +100

    -- Volatilidad
    volatility_regime ml.volatility_regime NOT NULL,
    current_atr DECIMAL(15, 8),
    atr_percentile DECIMAL(5, 2),                       -- Percentil historico
    expected_range_pips DECIMAL(10, 2),
    volatility_forecast DECIMAL(10, 4),                 -- Volatilidad esperada

    -- Niveles clave
    key_resistance_1 DECIMAL(15, 8),
    key_resistance_2 DECIMAL(15, 8),
    key_resistance_3 DECIMAL(15, 8),
    key_support_1 DECIMAL(15, 8),
    key_support_2 DECIMAL(15, 8),
    key_support_3 DECIMAL(15, 8),
    pivot_point DECIMAL(15, 8),

    -- Order blocks y FVGs
    bullish_order_blocks JSONB DEFAULT '[]'::JSONB,
    bearish_order_blocks JSONB DEFAULT '[]'::JSONB,
    fair_value_gaps JSONB DEFAULT '[]'::JSONB,
    liquidity_levels JSONB DEFAULT '[]'::JSONB,

    -- Indicadores
    indicators JSONB DEFAULT '{}'::JSONB,               -- RSI, MACD, etc.
    moving_averages JSONB DEFAULT '{}'::JSONB,          -- SMAs, EMAs

    -- Correlaciones
    correlation_dxy DECIMAL(5, 4),                      -- Correlacion con DXY
    correlation_gold DECIMAL(5, 4),                     -- Correlacion con oro
    correlation_sp500 DECIMAL(5, 4),                    -- Correlacion con S&P500
    correlated_pairs JSONB DEFAULT '[]'::JSONB,         -- Pares correlacionados

    -- Sentimiento
    sentiment_score DECIMAL(5, 2),                      -- -100 a +100
    sentiment_sources JSONB DEFAULT '{}'::JSONB,        -- Fuentes de sentimiento
    cot_report JSONB DEFAULT '{}'::JSONB,               -- Datos COT

    -- Eventos fundamentales
    upcoming_events JSONB DEFAULT '[]'::JSONB,          -- Eventos proximos
    recent_events_impact JSONB DEFAULT '[]'::JSONB,     -- Impacto de eventos recientes
    high_impact_event_today BOOLEAN NOT NULL DEFAULT FALSE,

    -- Escenarios
    primary_scenario JSONB DEFAULT '{}'::JSONB,         -- Escenario principal
    secondary_scenario JSONB DEFAULT '{}'::JSONB,       -- Escenario alternativo
    risk_scenario JSONB DEFAULT '{}'::JSONB,            -- Escenario de riesgo

    -- Zonas de interes
    buy_zones JSONB DEFAULT '[]'::JSONB,                -- Zonas de compra
    sell_zones JSONB DEFAULT '[]'::JSONB,               -- Zonas de venta
    avoid_zones JSONB DEFAULT '[]'::JSONB,              -- Zonas a evitar

    -- Modelo
    model_id VARCHAR(100),
    model_version VARCHAR(50) NOT NULL,
    analysis_confidence DECIMAL(5, 4) NOT NULL DEFAULT 0.5
        CHECK (analysis_confidence BETWEEN 0 AND 1),

    -- Resumen
    summary TEXT,                                       -- Resumen ejecutivo
    trading_plan TEXT,                                  -- Plan de trading sugerido
    key_insights JSONB DEFAULT '[]'::JSONB,             -- Insights clave

    -- Resultado (post-validacion)
    actual_direction VARCHAR(20),                       -- Direccion real
    actual_range_pips DECIMAL(10, 2),
    accuracy_score DECIMAL(5, 2),                       -- Score de precision
    validated_at TIMESTAMPTZ,

    -- Metadata
    tags VARCHAR(50)[],
    notes TEXT,
    metadata JSONB DEFAULT '{}'::JSONB,

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

    -- Constraints
    CONSTRAINT market_analysis_unique UNIQUE (tenant_id, symbol, analysis_type, analysis_date)
);

COMMENT ON TABLE ml.market_analysis IS
'Analisis de mercado generado por modelos ML: sesgo, estructura, volatilidad, niveles clave';

COMMENT ON COLUMN ml.market_analysis.bias IS
'Sesgo direccional del mercado para el periodo analizado';

COMMENT ON COLUMN ml.market_analysis.structure IS
'Estructura de mercado dominante (tendencia, rango, etc.)';

-- Indices
CREATE INDEX IF NOT EXISTS idx_market_analysis_tenant
    ON ml.market_analysis(tenant_id);

CREATE INDEX IF NOT EXISTS idx_market_analysis_symbol
    ON ml.market_analysis(symbol, analysis_date DESC);

CREATE INDEX IF NOT EXISTS idx_market_analysis_date
    ON ml.market_analysis(analysis_date DESC);

CREATE INDEX IF NOT EXISTS idx_market_analysis_type
    ON ml.market_analysis(analysis_type, analysis_date DESC);

CREATE INDEX IF NOT EXISTS idx_market_analysis_bias
    ON ml.market_analysis(bias, analysis_date DESC);

CREATE INDEX IF NOT EXISTS idx_market_analysis_active
    ON ml.market_analysis(valid_until)
    WHERE valid_until > NOW();

CREATE INDEX IF NOT EXISTS idx_market_analysis_model
    ON ml.market_analysis(model_version, analysis_date DESC);

CREATE INDEX IF NOT EXISTS idx_market_analysis_high_impact
    ON ml.market_analysis(analysis_date, high_impact_event_today)
    WHERE high_impact_event_today = TRUE;

-- GIN indices para JSONB
CREATE INDEX IF NOT EXISTS idx_market_analysis_events_gin
    ON ml.market_analysis USING GIN (upcoming_events);

CREATE INDEX IF NOT EXISTS idx_market_analysis_insights_gin
    ON ml.market_analysis USING GIN (key_insights);

-- Trigger para updated_at
DROP TRIGGER IF EXISTS market_analysis_updated_at ON ml.market_analysis;
CREATE TRIGGER market_analysis_updated_at
    BEFORE UPDATE ON ml.market_analysis
    FOR EACH ROW
    EXECUTE FUNCTION ml.update_ml_timestamp();

-- Funcion para obtener analisis actual
CREATE OR REPLACE FUNCTION ml.get_current_analysis(
    p_tenant_id UUID,
    p_symbol VARCHAR,
    p_analysis_type ml.analysis_type DEFAULT 'daily_bias'
)
RETURNS ml.market_analysis AS $$
DECLARE
    v_analysis ml.market_analysis;
BEGIN
    SELECT * INTO v_analysis
    FROM ml.market_analysis
    WHERE tenant_id = p_tenant_id
      AND symbol = p_symbol
      AND analysis_type = p_analysis_type
      AND valid_until > NOW()
    ORDER BY analysis_date DESC
    LIMIT 1;

    RETURN v_analysis;
END;
$$ LANGUAGE plpgsql;

-- Funcion para obtener sesgo agregado de multiples simbolos
CREATE OR REPLACE FUNCTION ml.get_market_overview(
    p_tenant_id UUID,
    p_symbols VARCHAR[] DEFAULT NULL
)
RETURNS TABLE (
    symbol VARCHAR,
    bias ml.market_bias,
    bias_confidence DECIMAL,
    structure ml.market_structure,
    volatility_regime ml.volatility_regime,
    analysis_date DATE
) AS $$
BEGIN
    RETURN QUERY
    SELECT DISTINCT ON (ma.symbol)
        ma.symbol,
        ma.bias,
        ma.bias_confidence,
        ma.structure,
        ma.volatility_regime,
        ma.analysis_date
    FROM ml.market_analysis ma
    WHERE ma.tenant_id = p_tenant_id
      AND ma.analysis_type = 'daily_bias'
      AND ma.valid_until > NOW()
      AND (p_symbols IS NULL OR ma.symbol = ANY(p_symbols))
    ORDER BY ma.symbol, ma.analysis_date DESC;
END;
$$ LANGUAGE plpgsql;

-- Funcion para validar analisis con datos reales
CREATE OR REPLACE FUNCTION ml.validate_market_analysis(
    p_analysis_id UUID,
    p_actual_high DECIMAL,
    p_actual_low DECIMAL,
    p_actual_close DECIMAL
)
RETURNS VOID AS $$
DECLARE
    v_analysis ml.market_analysis;
    v_direction VARCHAR;
    v_accuracy DECIMAL;
BEGIN
    SELECT * INTO v_analysis FROM ml.market_analysis WHERE id = p_analysis_id;

    IF NOT FOUND THEN
        RETURN;
    END IF;

    -- Determinar direccion real
    IF p_actual_close > (p_actual_high + p_actual_low) / 2 THEN
        v_direction := 'bullish';
    ELSE
        v_direction := 'bearish';
    END IF;

    -- Calcular accuracy basado en sesgo predicho vs real
    v_accuracy := CASE
        WHEN v_analysis.bias IN ('strong_bullish', 'bullish', 'slightly_bullish') AND v_direction = 'bullish' THEN 100
        WHEN v_analysis.bias IN ('strong_bearish', 'bearish', 'slightly_bearish') AND v_direction = 'bearish' THEN 100
        WHEN v_analysis.bias = 'neutral' THEN 50
        ELSE 0
    END;

    UPDATE ml.market_analysis
    SET actual_direction = v_direction,
        actual_range_pips = (p_actual_high - p_actual_low) * 10000,
        accuracy_score = v_accuracy,
        validated_at = NOW()
    WHERE id = p_analysis_id;
END;
$$ LANGUAGE plpgsql;

-- Vista de analisis activos
CREATE OR REPLACE VIEW ml.v_current_market_analysis AS
SELECT
    id,
    tenant_id,
    symbol,
    asset_class,
    analysis_type,
    analysis_date,
    bias,
    bias_confidence,
    structure,
    volatility_regime,
    expected_range_pips,
    key_resistance_1,
    key_support_1,
    pivot_point,
    sentiment_score,
    high_impact_event_today,
    summary,
    analysis_confidence,
    valid_until
FROM ml.market_analysis
WHERE valid_until > NOW()
ORDER BY analysis_date DESC, symbol;

-- Vista de rendimiento de analisis
CREATE OR REPLACE VIEW ml.v_market_analysis_performance AS
SELECT
    symbol,
    analysis_type,
    model_version,
    COUNT(*) AS total_analyses,
    ROUND(AVG(accuracy_score)::NUMERIC, 2) AS avg_accuracy,
    ROUND(AVG(bias_confidence)::NUMERIC, 4) AS avg_confidence,
    COUNT(*) FILTER (WHERE accuracy_score >= 70) AS accurate_count,
    COUNT(*) FILTER (WHERE accuracy_score < 30) AS inaccurate_count,
    ROUND((COUNT(*) FILTER (WHERE accuracy_score >= 70)::DECIMAL
        / NULLIF(COUNT(*) FILTER (WHERE validated_at IS NOT NULL), 0) * 100), 2) AS accuracy_rate
FROM ml.market_analysis
WHERE validated_at IS NOT NULL
GROUP BY symbol, analysis_type, model_version
ORDER BY accuracy_rate DESC NULLS LAST;

-- Vista de correlaciones actuales
CREATE OR REPLACE VIEW ml.v_market_correlations AS
SELECT
    symbol,
    analysis_date,
    correlation_dxy,
    correlation_gold,
    correlation_sp500,
    bias,
    structure
FROM ml.market_analysis
WHERE analysis_type = 'daily_bias'
  AND valid_until > NOW()
  AND (correlation_dxy IS NOT NULL OR correlation_gold IS NOT NULL)
ORDER BY analysis_date DESC, symbol;

-- RLS Policies
ALTER TABLE ml.market_analysis ENABLE ROW LEVEL SECURITY;

CREATE POLICY market_analysis_tenant ON ml.market_analysis
    FOR ALL
    USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);

-- Grants
GRANT SELECT, INSERT, UPDATE ON ml.market_analysis TO trading_app;
GRANT SELECT ON ml.market_analysis TO trading_readonly;
GRANT SELECT ON ml.v_current_market_analysis TO trading_app;
GRANT SELECT ON ml.v_market_analysis_performance TO trading_app;
GRANT SELECT ON ml.v_market_correlations TO trading_app;
GRANT EXECUTE ON FUNCTION ml.get_current_analysis TO trading_app;
GRANT EXECUTE ON FUNCTION ml.get_market_overview TO trading_app;
GRANT EXECUTE ON FUNCTION ml.validate_market_analysis TO trading_app;
