-- Migration 012: Create Event Processing and Configuration Tables
-- This migration creates the missing tables for event processing and configuration
-- Tables: market_events, trading_events, event_processing_stats, configuration, secrets

-- Enable required extensions if not already enabled
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- Market events table - stores market-related events
CREATE TABLE IF NOT EXISTS market_events (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    event_type VARCHAR(64) NOT NULL,
    symbol VARCHAR(32),
    "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL,
    event_data JSONB NOT NULL,
    source VARCHAR(64), -- Event source (exchange, internal, etc.)
    severity VARCHAR(20) DEFAULT 'info' CHECK (severity IN ('debug', 'info', 'warning', 'error', 'critical')),
    processed BOOLEAN DEFAULT FALSE,
    processed_at TIMESTAMP WITH TIME ZONE,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);

-- Trading events table - stores trading-related events
CREATE TABLE IF NOT EXISTS trading_events (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    event_type VARCHAR(64) NOT NULL,
    symbol VARCHAR(32),
    "order_id" UUID,
    account_id VARCHAR(64),
    "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL,
    event_data JSONB NOT NULL,
    "correlation_id" UUID, -- For tracing related events
    severity VARCHAR(20) DEFAULT 'info' CHECK (severity IN ('debug', 'info', 'warning', 'error', 'critical')),
    processed BOOLEAN DEFAULT FALSE,
    processed_at TIMESTAMP WITH TIME ZONE,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);

-- Event processing stats table - stores processing statistics
CREATE TABLE IF NOT EXISTS event_processing_stats (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    processor_name VARCHAR(128) NOT NULL,
    event_type VARCHAR(64) NOT NULL,
    "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL,
    events_processed INTEGER NOT NULL DEFAULT 0,
    events_failed INTEGER NOT NULL DEFAULT 0,
    average_processing_time_ms DECIMAL(10, 3),
    max_processing_time_ms DECIMAL(10, 3),
    min_processing_time_ms DECIMAL(10, 3),
    total_processing_time_ms BIGINT,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    UNIQUE(processor_name, event_type, "timestamp")
);

-- Configuration table - stores application configuration (if not already exists from config migration)
CREATE TABLE IF NOT EXISTS configuration (
    id SERIAL PRIMARY KEY,
    key VARCHAR(256) NOT NULL UNIQUE,
    value TEXT NOT NULL,
    value_type VARCHAR(32) NOT NULL DEFAULT 'string' CHECK (value_type IN ('string', 'number', 'boolean', 'json')),
    description TEXT,
    category VARCHAR(128),
    environment VARCHAR(32) DEFAULT 'development',
    is_sensitive BOOLEAN DEFAULT FALSE,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    created_by VARCHAR(128),
    updated_by VARCHAR(128)
);

-- Secrets table - stores encrypted sensitive configuration
CREATE TABLE IF NOT EXISTS secrets (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    key VARCHAR(256) NOT NULL,
    encrypted_value BYTEA NOT NULL,
    key_version INTEGER NOT NULL DEFAULT 1,
    environment VARCHAR(32) DEFAULT 'development',
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    expires_at TIMESTAMP WITH TIME ZONE,
    created_by VARCHAR(128),
    updated_by VARCHAR(128),
    UNIQUE(key, environment)
);

-- Risk-related tables that were referenced
CREATE TABLE IF NOT EXISTS risk_alerts (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    alert_type VARCHAR(64) NOT NULL,
    symbol VARCHAR(32),
    account_id VARCHAR(64),
    severity VARCHAR(20) NOT NULL CHECK (severity IN ('low', 'medium', 'high', 'critical')),
    message TEXT NOT NULL,
    threshold_value DECIMAL(20, 8),
    current_value DECIMAL(20, 8),
    metadata JSONB,
    acknowledged BOOLEAN DEFAULT FALSE,
    acknowledged_by VARCHAR(128),
    acknowledged_at TIMESTAMP WITH TIME ZONE,
    resolved BOOLEAN DEFAULT FALSE,
    resolved_by VARCHAR(128),
    resolved_at TIMESTAMP WITH TIME ZONE,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS position_risks (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    symbol VARCHAR(32) NOT NULL,
    account_id VARCHAR(64),
    position_size BIGINT NOT NULL,
    market_value DECIMAL(20, 8) NOT NULL,
    unrealized_pnl DECIMAL(20, 8),
    var_1d DECIMAL(20, 8), -- 1-day Value at Risk
    var_10d DECIMAL(20, 8), -- 10-day Value at Risk
    exposure_pct DECIMAL(10, 6), -- Exposure as percentage of total portfolio
    concentration_risk DECIMAL(10, 6),
    liquidity_risk DECIMAL(10, 6),
    calculated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    UNIQUE(symbol, account_id, calculated_at)
);

CREATE TABLE IF NOT EXISTS var_calculations (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    portfolio_id VARCHAR(128) NOT NULL,
    calculation_date DATE NOT NULL,
    confidence_level DECIMAL(5, 4) NOT NULL, -- e.g., 0.99 for 99%
    time_horizon_days INTEGER NOT NULL,
    var_amount DECIMAL(20, 8) NOT NULL,
    expected_shortfall DECIMAL(20, 8), -- Conditional VaR
    calculation_method VARCHAR(64) NOT NULL, -- historical, parametric, monte_carlo
    model_parameters JSONB,
    calculation_time_ms INTEGER,
    calculated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    UNIQUE(portfolio_id, calculation_date, confidence_level, time_horizon_days)
);

-- Create indexes for optimal query performance

-- Market events indexes (only create if table was created by this migration, not migration 001)
DO $$
BEGIN
    -- Check if market_events has the "timestamp" column (our schema) vs event_timestamp (migration 001 schema)
    IF EXISTS (SELECT 1 FROM information_schema.columns
               WHERE table_name = 'market_events' AND column_name = 'timestamp') THEN
        CREATE INDEX IF NOT EXISTS idx_market_events_type_timestamp ON market_events(event_type, "timestamp" DESC);
        CREATE INDEX IF NOT EXISTS idx_market_events_symbol_timestamp ON market_events(symbol, "timestamp" DESC);
        CREATE INDEX IF NOT EXISTS idx_market_events_timestamp ON market_events("timestamp" DESC);
        CREATE INDEX IF NOT EXISTS idx_market_events_processed ON market_events(processed, "timestamp" DESC);
    END IF;
END $$;

-- Trading events indexes (only create if table was created by this migration, not migration 001)
DO $$
BEGIN
    -- Check if trading_events has the "timestamp" column (our schema) vs event_timestamp (migration 001 schema)
    IF EXISTS (SELECT 1 FROM information_schema.columns
               WHERE table_name = 'trading_events' AND column_name = 'timestamp') THEN
        CREATE INDEX IF NOT EXISTS idx_trading_events_type_timestamp ON trading_events(event_type, "timestamp" DESC);
        CREATE INDEX IF NOT EXISTS idx_trading_events_symbol_timestamp ON trading_events(symbol, "timestamp" DESC);
        CREATE INDEX IF NOT EXISTS idx_trading_events_order_id ON trading_events("order_id");
        CREATE INDEX IF NOT EXISTS idx_trading_events_correlation_id ON trading_events("correlation_id");
        CREATE INDEX IF NOT EXISTS idx_trading_events_timestamp ON trading_events("timestamp" DESC);
    END IF;
END $$;

-- Event processing stats indexes (always create as this table is new)
CREATE INDEX IF NOT EXISTS idx_event_processing_stats_processor_type ON event_processing_stats(processor_name, event_type, "timestamp" DESC);

-- Configuration indexes
CREATE INDEX IF NOT EXISTS idx_configuration_category ON configuration(category);
CREATE INDEX IF NOT EXISTS idx_configuration_environment ON configuration(environment);

-- Secrets indexes
CREATE INDEX IF NOT EXISTS idx_secrets_environment ON secrets(environment);
CREATE INDEX IF NOT EXISTS idx_secrets_expires_at ON secrets(expires_at);

-- Risk alerts indexes
CREATE INDEX IF NOT EXISTS idx_risk_alerts_type_severity ON risk_alerts(alert_type, severity, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_risk_alerts_symbol ON risk_alerts(symbol, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_risk_alerts_unresolved ON risk_alerts(resolved, created_at DESC) WHERE NOT resolved;

-- Position risks indexes
CREATE INDEX IF NOT EXISTS idx_position_risks_symbol_date ON position_risks(symbol, calculated_at DESC);
CREATE INDEX IF NOT EXISTS idx_position_risks_account_date ON position_risks(account_id, calculated_at DESC);

-- VaR calculations indexes
CREATE INDEX IF NOT EXISTS idx_var_calculations_portfolio_date ON var_calculations(portfolio_id, calculation_date DESC);

-- Add triggers for updating timestamps
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ language 'plpgsql';

-- Apply update triggers
CREATE TRIGGER update_configuration_updated_at BEFORE UPDATE ON configuration
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

CREATE TRIGGER update_secrets_updated_at BEFORE UPDATE ON secrets
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

-- Add table comments
COMMENT ON TABLE market_events IS 'Market-related events from exchanges and internal systems';
COMMENT ON TABLE trading_events IS 'Trading-related events including orders, fills, and position changes';
COMMENT ON TABLE event_processing_stats IS 'Statistics and metrics for event processing performance';
COMMENT ON TABLE configuration IS 'Application configuration key-value pairs';
COMMENT ON TABLE secrets IS 'Encrypted sensitive configuration data';
COMMENT ON TABLE risk_alerts IS 'Risk management alerts and notifications';
COMMENT ON TABLE position_risks IS 'Position-level risk calculations and metrics';
COMMENT ON TABLE var_calculations IS 'Value at Risk calculations for portfolios';

-- Grant permissions (assuming the trading service user exists from previous migrations)
DO $$
BEGIN
    IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'trading_service') THEN
        GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO trading_service;
        GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO trading_service;
    END IF;
END
$$;