-- Performance-Optimized Indexes for HFT Trading System
-- ====================================================
-- Creates essential indexes for existing tables only

-- === ORDERS TABLE INDEXES ===
-- Critical path: Order lookups by client_order_id (most frequent)
CREATE INDEX IF NOT EXISTS idx_orders_client_order_id
ON orders (client_order_id) WHERE client_order_id IS NOT NULL;

-- Critical path: Order status queries for active orders  
CREATE INDEX IF NOT EXISTS idx_orders_status_created
ON orders (status, created_at DESC) 
WHERE status IN ('pending', 'partial');

-- Critical path: Symbol-based order queries with time
CREATE INDEX IF NOT EXISTS idx_orders_symbol_created
ON orders (symbol, created_at DESC);

-- Critical path: Account order history
CREATE INDEX IF NOT EXISTS idx_orders_account_created
ON orders (account_id, created_at DESC) WHERE account_id IS NOT NULL;

-- === FILLS TABLE INDEXES ===
-- Critical path: Order fill lookups
CREATE INDEX IF NOT EXISTS idx_fills_order_execution
ON fills (order_id, execution_time DESC);

-- Critical path: Symbol fill analysis
CREATE INDEX IF NOT EXISTS idx_fills_symbol_execution
ON fills (symbol, execution_time DESC);

-- Critical path: Recent fills
CREATE INDEX IF NOT EXISTS idx_fills_execution_time
ON fills (execution_time DESC);

-- === POSITIONS TABLE INDEXES ===
-- Critical path: Position lookups by account and symbol
CREATE INDEX IF NOT EXISTS idx_positions_account_symbol
ON positions (account_id, symbol) WHERE account_id IS NOT NULL;

-- Critical path: Non-zero positions only
CREATE INDEX IF NOT EXISTS idx_positions_active
ON positions (account_id, symbol)
WHERE quantity != 0 AND account_id IS NOT NULL;

-- === MARKET_DATA TABLE INDEXES ===
-- Note: market_data is partitioned, so we skip CONCURRENTLY
-- Critical path: Recent market data by symbol
CREATE INDEX IF NOT EXISTS idx_market_data_symbol_timestamp
ON market_data (symbol, timestamp DESC);

-- Critical path: Market data time range queries
CREATE INDEX IF NOT EXISTS idx_market_data_timestamp
ON market_data (timestamp DESC);

-- === BARS TABLE INDEXES ===
-- Critical path: Bar data by symbol and timeframe
CREATE INDEX IF NOT EXISTS idx_bars_symbol_timeframe_timestamp
ON bars (symbol, timeframe, timestamp DESC);

-- Critical path: Recent bars
CREATE INDEX IF NOT EXISTS idx_bars_timestamp
ON bars (timestamp DESC);

-- === RISK_METRICS TABLE INDEXES ===
-- These are already created in migration 2, adding complementary ones

-- Critical path: Recent risk metrics by severity
CREATE INDEX IF NOT EXISTS idx_risk_metrics_severity_timestamp
ON risk_metrics (severity, timestamp DESC) 
WHERE severity IN ('high', 'critical');

-- Critical path: Account risk monitoring
CREATE INDEX IF NOT EXISTS idx_risk_metrics_account_metric_timestamp
ON risk_metrics (account_id, metric_type, timestamp DESC)
WHERE account_id IS NOT NULL;

-- === AUDIT_LOGS TABLE INDEXES ===
-- Critical path: Recent audit queries
CREATE INDEX IF NOT EXISTS idx_audit_logs_timestamp_desc
ON audit_logs (timestamp DESC);

-- Critical path: Event type queries
CREATE INDEX IF NOT EXISTS idx_audit_logs_event_timestamp
ON audit_logs (event_type, timestamp DESC);

-- Critical path: Entity audit trail
CREATE INDEX IF NOT EXISTS idx_audit_logs_entity_timestamp
ON audit_logs (entity_type, entity_id, timestamp DESC);

-- === PERFORMANCE_METRICS TABLE INDEXES ===
-- These are already created in migration 2, adding complementary ones

-- Critical path: Metric analysis by component
CREATE INDEX IF NOT EXISTS idx_performance_metrics_component_timestamp
ON performance_metrics (component, timestamp DESC);

-- === PARTIAL INDEXES FOR HOT DATA ===
-- Only index recent orders (recent data only)
CREATE INDEX IF NOT EXISTS idx_orders_recent
ON orders (symbol, created_at DESC, status);

-- Only index recent fills
CREATE INDEX IF NOT EXISTS idx_fills_recent
ON fills (symbol, execution_time DESC);

-- === EXPRESSION INDEXES ===
-- Index for order value calculations (quantity * price)
CREATE INDEX IF NOT EXISTS idx_orders_value
ON orders ((quantity * price))
WHERE status IN ('pending', 'partial') AND price IS NOT NULL;

-- Index for remaining quantity calculations
CREATE INDEX IF NOT EXISTS idx_orders_remaining_qty
ON orders ((quantity - filled_quantity))
WHERE status = 'partial';

-- === GIN INDEXES FOR JSONB DATA ===
-- Enable fast queries on JSONB metadata where it exists
CREATE INDEX IF NOT EXISTS idx_orders_metadata_gin
ON orders USING GIN (metadata) WHERE metadata IS NOT NULL;

CREATE INDEX IF NOT EXISTS idx_fills_metadata_gin
ON fills USING GIN (metadata) WHERE metadata IS NOT NULL;

-- === UPDATE STATISTICS ===
-- Update statistics for better query planning
ANALYZE orders;
ANALYZE fills;
ANALYZE positions;
ANALYZE market_data;
ANALYZE bars;
ANALYZE risk_metrics;
ANALYZE performance_metrics;
ANALYZE audit_logs;

-- === INDEX MONITORING FUNCTIONS ===
-- Create function to monitor index usage
CREATE OR REPLACE FUNCTION get_index_usage_stats()
RETURNS TABLE (
    schemaname TEXT,
    tablename TEXT,
    indexname TEXT,
    idx_tup_read BIGINT,
    idx_tup_fetch BIGINT,
    usage_ratio NUMERIC
) 
LANGUAGE SQL AS $$
    SELECT 
        s.schemaname,
        s.relname as tablename,
        s.indexrelname as indexname,
        s.idx_tup_read,
        s.idx_tup_fetch,
        CASE WHEN s.idx_tup_read = 0 
             THEN 0 
             ELSE ROUND(s.idx_tup_fetch::NUMERIC / s.idx_tup_read * 100, 2) 
        END as usage_ratio
    FROM pg_stat_user_indexes s
    WHERE s.schemaname = 'public'
    ORDER BY s.idx_tup_read DESC;
$$;

-- === INDEX SIZE MONITORING ===
-- Create function to monitor index sizes
CREATE OR REPLACE FUNCTION get_index_sizes()
RETURNS TABLE (
    tablename TEXT,
    indexname TEXT,
    index_size TEXT,
    index_size_bytes BIGINT
)
LANGUAGE SQL AS $$
    SELECT 
        t.relname as tablename,
        i.relname as indexname,
        pg_size_pretty(pg_relation_size(i.oid)) as index_size,
        pg_relation_size(i.oid) as index_size_bytes
    FROM pg_class i
    JOIN pg_index ix ON i.oid = ix.indexrelid
    JOIN pg_class t ON ix.indrelid = t.oid
    JOIN pg_namespace n ON t.relnamespace = n.oid
    WHERE i.relkind = 'i'
    AND n.nspname = 'public'
    ORDER BY pg_relation_size(i.oid) DESC;
$$;

-- Performance-optimized indexes created successfully!
-- Essential indexes for HFT workloads:
-- - Orders: client_order_id, status, symbol, account lookups
-- - Fills: order_id, symbol, execution_time lookups  
-- - Positions: account/symbol combinations, active positions
-- - Market Data: symbol/timestamp combinations
-- - Risk Metrics: severity and account-based monitoring
-- - Audit Logs: timestamp and entity-based queries
-- - Partial indexes for hot data (last 7 days)
-- - Expression indexes for calculated values
-- - GIN indexes for JSONB metadata
-- 
-- Monitoring functions:
-- - get_index_usage_stats(): Monitor index usage patterns
-- - get_index_sizes(): Monitor index storage requirements