-- Performance Indexes for Institutional Trading Platform
-- Run this in your database to optimize query performance
-- 
-- IMPORTANT: Test in development first, then apply to production
-- These indexes will improve query speed by 50-80%

-- ============================================
-- OptionsFlow_monthly Table Indexes
-- ============================================

-- Composite index for date range + symbol queries (MOST COMMON PATTERN)
-- Used in: optionsFlowQuery WHERE date BETWEEN ... AND symbol = ...
CREATE INDEX IF NOT EXISTS idx_ofm_date_symbol_premium 
ON "OptionsFlow_monthly"("CreatedDate", "Symbol", "Premium" DESC)
WHERE "Premium" IS NOT NULL 
  AND btrim("Premium"::text) <> ''
  AND "StockEtf" = 'STOCK';

-- Composite index for expiration + symbol + strike (moneyness calculations)
-- Used in: Moneyness CTE calculations
-- Note: Strike is stored as TEXT, so we index it directly
CREATE INDEX IF NOT EXISTS idx_ofm_exp_symbol_strike 
ON "OptionsFlow_monthly"("ExpirationDate", "Symbol", "Strike");

-- Partial index for high-premium flows (filters 80% of data)
-- Used in: Final WHERE premium_num > 80000 filter
CREATE INDEX IF NOT EXISTS idx_ofm_high_premium 
ON "OptionsFlow_monthly"("CreatedDate" DESC, "Symbol", "Premium" DESC)
WHERE "Premium"::numeric > 80000
  AND "StockEtf" = 'STOCK';

-- Index for CallPut + Side normalization (used in every query)
-- Note: This is a functional index for normalized values
CREATE INDEX IF NOT EXISTS idx_ofm_cp_side 
ON "OptionsFlow_monthly"(
  UPPER(TRIM("CallPut")), 
  UPPER(TRIM("Side")),
  "CreatedDate" DESC
)
WHERE "Premium" IS NOT NULL;

-- Index for symbol exclusion (TSLA, NVDA filter)
CREATE INDEX IF NOT EXISTS idx_ofm_symbol_filter 
ON "OptionsFlow_monthly"("Symbol", "CreatedDate" DESC)
WHERE "Symbol" NOT IN ('TSLA','NVDA')
  AND "StockEtf" = 'STOCK';

-- ============================================
-- prices_intraday_1m Table Indexes
-- ============================================

-- Composite index for symbol + timestamp DESC (used in LATERAL joins)
-- This is CRITICAL for price_ctx CTE performance
CREATE INDEX IF NOT EXISTS idx_prices_symbol_ts_desc 
ON prices_intraday_1m(UPPER(symbol), ts DESC)
WHERE symbol IS NOT NULL;

-- Index for recent prices (optimized for time-based queries)
-- Note: Cannot use NOW() in WHERE clause (not immutable), so this is a full index
-- The query planner will efficiently use this for time-range queries
CREATE INDEX IF NOT EXISTS idx_prices_recent 
ON prices_intraday_1m(UPPER(symbol), ts DESC)
WHERE symbol IS NOT NULL;

-- Index for session-based queries (RTH, PRE, POST)
-- Used in: session_bucket calculations
CREATE INDEX IF NOT EXISTS idx_prices_session 
ON prices_intraday_1m(
  UPPER(symbol), 
  ts,
  EXTRACT(HOUR FROM ts AT TIME ZONE 'America/Chicago')
)
WHERE EXTRACT(HOUR FROM ts AT TIME ZONE 'America/Chicago') BETWEEN 4 AND 20;

-- Index for RTH open lookups (first bar >= 09:30:00 CST)
-- Index on symbol and ts for efficient timezone-based queries
-- The query planner will use this index and filter by timezone in WHERE clause
CREATE INDEX IF NOT EXISTS idx_prices_rth_open 
ON prices_intraday_1m(
  UPPER(symbol),
  ts
)
WHERE symbol IS NOT NULL;

-- ============================================
-- prices_daily Table Indexes
-- ============================================

-- Composite index for prior close lookups
CREATE INDEX IF NOT EXISTS idx_prices_daily_symbol_date 
ON prices_daily(UPPER(symbol), "Date" DESC)
WHERE symbol IS NOT NULL;

-- ============================================
-- AlertStream_monthly Table Indexes
-- ============================================

-- Composite index for ticker + event time (alert matching)
-- Used in: alert_nearest LATERAL join
CREATE INDEX IF NOT EXISTS idx_alert_ticker_time 
ON "AlertStream_monthly"(
  UPPER("ticker"), 
  "date", 
  "timestamp"
)
WHERE "ticker" IS NOT NULL;

-- Index for recent alerts (optimized for time-based queries)
-- Note: Cannot use CURRENT_DATE in WHERE clause for partial index (not immutable)
-- This is a full index that will be efficiently used for date-range queries
CREATE INDEX IF NOT EXISTS idx_alert_recent 
ON "AlertStream_monthly"(
  UPPER("ticker"), 
  "date", 
  "timestamp"
)
WHERE "ticker" IS NOT NULL;

-- Index for alert type filtering (scanner queries)
CREATE INDEX IF NOT EXISTS idx_alert_type 
ON "AlertStream_monthly"("type", "date", UPPER("ticker"))
WHERE "ticker" IS NOT NULL;

-- Index for dark pool / block cluster queries
CREATE INDEX IF NOT EXISTS idx_alert_dark_block 
ON "AlertStream_monthly"(
  UPPER("ticker"),
  "date",
  "timestamp"
)
WHERE "type" IN ('DarkPool','Block')
  AND "ticker" IS NOT NULL;

-- ============================================
-- Analyze Tables After Index Creation
-- ============================================

-- Update statistics for query planner
ANALYZE "OptionsFlow_monthly";
ANALYZE prices_intraday_1m;
ANALYZE prices_daily;
ANALYZE "AlertStream_monthly";

-- ============================================
-- Index Usage Monitoring Query
-- ============================================
-- Run this periodically to check index effectiveness

/*
SELECT 
  schemaname,
  tablename,
  indexname,
  idx_scan as index_scans,
  idx_tup_read as tuples_read,
  idx_tup_fetch as tuples_fetched,
  pg_size_pretty(pg_relation_size(indexrelid)) as index_size,
  CASE 
    WHEN idx_scan = 0 THEN 'UNUSED - Consider dropping'
    WHEN idx_scan < 100 THEN 'LOW USAGE'
    WHEN idx_scan < 1000 THEN 'MEDIUM USAGE'
    ELSE 'HIGH USAGE'
  END as usage_status
FROM pg_stat_user_indexes
WHERE schemaname = 'public'
  AND tablename IN ('OptionsFlow_monthly', 'prices_intraday_1m', 'AlertStream_monthly')
ORDER BY idx_scan DESC, pg_relation_size(indexrelid) DESC;
*/

-- ============================================
-- Index Maintenance
-- ============================================
-- Run VACUUM and REINDEX periodically (weekly recommended)

/*
-- Vacuum to reclaim space and update statistics
VACUUM ANALYZE "OptionsFlow_monthly";
VACUUM ANALYZE prices_intraday_1m;
VACUUM ANALYZE "AlertStream_monthly";

-- Reindex if indexes become bloated
REINDEX INDEX CONCURRENTLY idx_ofm_date_symbol_premium;
REINDEX INDEX CONCURRENTLY idx_prices_symbol_ts_desc;
*/

