-- =====================================================
-- ML SCHEMA - CALCULATE PREDICTION ACCURACY FUNCTION
-- =====================================================
-- Description: Function to calculate LLM prediction accuracy metrics
-- Schema: ml
-- Author: Database Agent
-- Date: 2026-01-04
-- Module: OQI-010-llm-trading-integration
-- =====================================================

-- -----------------------------------------------------
-- Function: ml.calculate_llm_prediction_accuracy
-- -----------------------------------------------------
-- Calculates accuracy metrics for LLM predictions
-- Parameters:
--   p_symbol: Trading symbol (required)
--   p_days: Number of days to analyze (default: 30)
-- Returns:
--   total_predictions: Total number of resolved predictions
--   direction_accuracy: Percentage of correct direction predictions
--   target_hit_rate: Percentage of predictions that hit take profit
--   avg_pnl_pips: Average profit/loss in pips
--   profit_factor: Ratio of gross profit to gross loss
--   win_rate: Percentage of profitable trades
--   avg_resolution_candles: Average candles to resolution
-- -----------------------------------------------------

CREATE OR REPLACE FUNCTION ml.calculate_llm_prediction_accuracy(
  p_symbol VARCHAR,
  p_days INT DEFAULT 30
)
RETURNS TABLE(
  total_predictions INT,
  direction_accuracy DECIMAL(5,4),
  target_hit_rate DECIMAL(5,4),
  stop_hit_rate DECIMAL(5,4),
  avg_pnl_pips DECIMAL(10,2),
  profit_factor DECIMAL(10,4),
  win_rate DECIMAL(5,4),
  avg_resolution_candles DECIMAL(10,2)
) AS $$
BEGIN
  RETURN QUERY
  SELECT
    COUNT(*)::INT AS total_predictions,

    -- Direction accuracy (correct predictions / total)
    COALESCE(
      AVG(CASE WHEN o.direction_correct = TRUE THEN 1.0 ELSE 0.0 END)::DECIMAL(5,4),
      0.0
    ) AS direction_accuracy,

    -- Target hit rate (predictions that reached take profit)
    COALESCE(
      AVG(CASE WHEN o.target_reached = TRUE THEN 1.0 ELSE 0.0 END)::DECIMAL(5,4),
      0.0
    ) AS target_hit_rate,

    -- Stop hit rate (predictions that hit stop loss)
    COALESCE(
      AVG(CASE WHEN o.stop_hit = TRUE THEN 1.0 ELSE 0.0 END)::DECIMAL(5,4),
      0.0
    ) AS stop_hit_rate,

    -- Average PnL in pips
    COALESCE(AVG(o.pnl_pips)::DECIMAL(10,2), 0.0) AS avg_pnl_pips,

    -- Profit factor (gross profit / gross loss)
    CASE
      WHEN COALESCE(SUM(CASE WHEN o.pnl_pips < 0 THEN ABS(o.pnl_pips) ELSE 0 END), 0) > 0
      THEN (
        COALESCE(SUM(CASE WHEN o.pnl_pips > 0 THEN o.pnl_pips ELSE 0 END), 0) /
        SUM(CASE WHEN o.pnl_pips < 0 THEN ABS(o.pnl_pips) ELSE 0 END)
      )::DECIMAL(10,4)
      ELSE NULL
    END AS profit_factor,

    -- Win rate (profitable trades / total)
    COALESCE(
      AVG(CASE WHEN o.pnl_pips > 0 THEN 1.0 ELSE 0.0 END)::DECIMAL(5,4),
      0.0
    ) AS win_rate,

    -- Average candles to resolution
    COALESCE(AVG(o.resolution_candles)::DECIMAL(10,2), 0.0) AS avg_resolution_candles

  FROM ml.llm_predictions p
  INNER JOIN ml.llm_prediction_outcomes o ON p.id = o.prediction_id
  WHERE p.symbol = p_symbol
    AND p.created_at >= NOW() - (p_days || ' days')::INTERVAL
    AND o.resolved_at IS NOT NULL;
END;
$$ LANGUAGE plpgsql STABLE;

COMMENT ON FUNCTION ml.calculate_llm_prediction_accuracy(VARCHAR, INT) IS
'Calculates comprehensive accuracy metrics for LLM predictions.

Parameters:
  - p_symbol: Trading symbol to analyze (e.g., XAUUSD, BTCUSDT)
  - p_days: Number of days to look back (default: 30)

Returns:
  - total_predictions: Count of resolved predictions in period
  - direction_accuracy: Ratio of correct direction predictions (0.0 to 1.0)
  - target_hit_rate: Ratio of predictions that hit take profit (0.0 to 1.0)
  - stop_hit_rate: Ratio of predictions that hit stop loss (0.0 to 1.0)
  - avg_pnl_pips: Average profit/loss in pips
  - profit_factor: Gross profit / Gross loss (>1.0 is profitable)
  - win_rate: Ratio of profitable trades (0.0 to 1.0)
  - avg_resolution_candles: Average candles until outcome determined

Example usage:
  SELECT * FROM ml.calculate_llm_prediction_accuracy(''XAUUSD'', 30);
  SELECT * FROM ml.calculate_llm_prediction_accuracy(''BTCUSDT'', 7);
';


-- -----------------------------------------------------
-- Function: ml.calculate_llm_prediction_accuracy_by_phase
-- -----------------------------------------------------
-- Calculates accuracy metrics grouped by AMD phase
-- -----------------------------------------------------

CREATE OR REPLACE FUNCTION ml.calculate_llm_prediction_accuracy_by_phase(
  p_symbol VARCHAR,
  p_days INT DEFAULT 30
)
RETURNS TABLE(
  amd_phase VARCHAR(50),
  total_predictions INT,
  direction_accuracy DECIMAL(5,4),
  avg_pnl_pips DECIMAL(10,2),
  win_rate DECIMAL(5,4)
) AS $$
BEGIN
  RETURN QUERY
  SELECT
    p.amd_phase,
    COUNT(*)::INT AS total_predictions,
    COALESCE(
      AVG(CASE WHEN o.direction_correct = TRUE THEN 1.0 ELSE 0.0 END)::DECIMAL(5,4),
      0.0
    ) AS direction_accuracy,
    COALESCE(AVG(o.pnl_pips)::DECIMAL(10,2), 0.0) AS avg_pnl_pips,
    COALESCE(
      AVG(CASE WHEN o.pnl_pips > 0 THEN 1.0 ELSE 0.0 END)::DECIMAL(5,4),
      0.0
    ) AS win_rate
  FROM ml.llm_predictions p
  INNER JOIN ml.llm_prediction_outcomes o ON p.id = o.prediction_id
  WHERE p.symbol = p_symbol
    AND p.created_at >= NOW() - (p_days || ' days')::INTERVAL
    AND o.resolved_at IS NOT NULL
    AND p.amd_phase IS NOT NULL
  GROUP BY p.amd_phase
  ORDER BY total_predictions DESC;
END;
$$ LANGUAGE plpgsql STABLE;

COMMENT ON FUNCTION ml.calculate_llm_prediction_accuracy_by_phase(VARCHAR, INT) IS
'Calculates prediction accuracy metrics grouped by AMD phase.

Useful for understanding which AMD phases produce the most accurate predictions.

Example usage:
  SELECT * FROM ml.calculate_llm_prediction_accuracy_by_phase(''XAUUSD'', 30);
';


-- -----------------------------------------------------
-- Function: ml.calculate_llm_prediction_accuracy_by_killzone
-- -----------------------------------------------------
-- Calculates accuracy metrics grouped by ICT Killzone
-- -----------------------------------------------------

CREATE OR REPLACE FUNCTION ml.calculate_llm_prediction_accuracy_by_killzone(
  p_symbol VARCHAR,
  p_days INT DEFAULT 30
)
RETURNS TABLE(
  killzone VARCHAR(50),
  total_predictions INT,
  direction_accuracy DECIMAL(5,4),
  avg_pnl_pips DECIMAL(10,2),
  win_rate DECIMAL(5,4)
) AS $$
BEGIN
  RETURN QUERY
  SELECT
    p.killzone,
    COUNT(*)::INT AS total_predictions,
    COALESCE(
      AVG(CASE WHEN o.direction_correct = TRUE THEN 1.0 ELSE 0.0 END)::DECIMAL(5,4),
      0.0
    ) AS direction_accuracy,
    COALESCE(AVG(o.pnl_pips)::DECIMAL(10,2), 0.0) AS avg_pnl_pips,
    COALESCE(
      AVG(CASE WHEN o.pnl_pips > 0 THEN 1.0 ELSE 0.0 END)::DECIMAL(5,4),
      0.0
    ) AS win_rate
  FROM ml.llm_predictions p
  INNER JOIN ml.llm_prediction_outcomes o ON p.id = o.prediction_id
  WHERE p.symbol = p_symbol
    AND p.created_at >= NOW() - (p_days || ' days')::INTERVAL
    AND o.resolved_at IS NOT NULL
    AND p.killzone IS NOT NULL
  GROUP BY p.killzone
  ORDER BY total_predictions DESC;
END;
$$ LANGUAGE plpgsql STABLE;

COMMENT ON FUNCTION ml.calculate_llm_prediction_accuracy_by_killzone(VARCHAR, INT) IS
'Calculates prediction accuracy metrics grouped by ICT Killzone.

Useful for understanding which trading sessions produce the best predictions.

Example usage:
  SELECT * FROM ml.calculate_llm_prediction_accuracy_by_killzone(''XAUUSD'', 30);
';


-- -----------------------------------------------------
-- Function: ml.calculate_llm_prediction_accuracy_by_confluence
-- -----------------------------------------------------
-- Calculates accuracy metrics grouped by confluence score ranges
-- -----------------------------------------------------

CREATE OR REPLACE FUNCTION ml.calculate_llm_prediction_accuracy_by_confluence(
  p_symbol VARCHAR,
  p_days INT DEFAULT 30
)
RETURNS TABLE(
  confluence_range VARCHAR(20),
  total_predictions INT,
  direction_accuracy DECIMAL(5,4),
  avg_pnl_pips DECIMAL(10,2),
  win_rate DECIMAL(5,4)
) AS $$
BEGIN
  RETURN QUERY
  SELECT
    CASE
      WHEN p.confluence_score >= 0.8 THEN '0.8-1.0 (High)'
      WHEN p.confluence_score >= 0.6 THEN '0.6-0.8 (Medium-High)'
      WHEN p.confluence_score >= 0.4 THEN '0.4-0.6 (Medium)'
      WHEN p.confluence_score >= 0.2 THEN '0.2-0.4 (Medium-Low)'
      ELSE '0.0-0.2 (Low)'
    END AS confluence_range,
    COUNT(*)::INT AS total_predictions,
    COALESCE(
      AVG(CASE WHEN o.direction_correct = TRUE THEN 1.0 ELSE 0.0 END)::DECIMAL(5,4),
      0.0
    ) AS direction_accuracy,
    COALESCE(AVG(o.pnl_pips)::DECIMAL(10,2), 0.0) AS avg_pnl_pips,
    COALESCE(
      AVG(CASE WHEN o.pnl_pips > 0 THEN 1.0 ELSE 0.0 END)::DECIMAL(5,4),
      0.0
    ) AS win_rate
  FROM ml.llm_predictions p
  INNER JOIN ml.llm_prediction_outcomes o ON p.id = o.prediction_id
  WHERE p.symbol = p_symbol
    AND p.created_at >= NOW() - (p_days || ' days')::INTERVAL
    AND o.resolved_at IS NOT NULL
    AND p.confluence_score IS NOT NULL
  GROUP BY
    CASE
      WHEN p.confluence_score >= 0.8 THEN '0.8-1.0 (High)'
      WHEN p.confluence_score >= 0.6 THEN '0.6-0.8 (Medium-High)'
      WHEN p.confluence_score >= 0.4 THEN '0.4-0.6 (Medium)'
      WHEN p.confluence_score >= 0.2 THEN '0.2-0.4 (Medium-Low)'
      ELSE '0.0-0.2 (Low)'
    END
  ORDER BY confluence_range DESC;
END;
$$ LANGUAGE plpgsql STABLE;

COMMENT ON FUNCTION ml.calculate_llm_prediction_accuracy_by_confluence(VARCHAR, INT) IS
'Calculates prediction accuracy metrics grouped by confluence score ranges.

Validates whether higher confluence scores correlate with better accuracy.

Example usage:
  SELECT * FROM ml.calculate_llm_prediction_accuracy_by_confluence(''XAUUSD'', 30);
';


-- -----------------------------------------------------
-- Function: ml.get_active_risk_events
-- -----------------------------------------------------
-- Returns all unresolved risk events for a user
-- -----------------------------------------------------

CREATE OR REPLACE FUNCTION ml.get_active_risk_events(
  p_user_id UUID DEFAULT NULL
)
RETURNS TABLE(
  id UUID,
  event_type VARCHAR(50),
  severity VARCHAR(20),
  details JSONB,
  action_taken VARCHAR(100),
  created_at TIMESTAMPTZ
) AS $$
BEGIN
  RETURN QUERY
  SELECT
    r.id,
    r.event_type,
    r.severity,
    r.details,
    r.action_taken,
    r.created_at
  FROM ml.risk_events r
  WHERE r.resolved = FALSE
    AND (p_user_id IS NULL OR r.user_id = p_user_id OR r.user_id IS NULL)
  ORDER BY
    CASE r.severity
      WHEN 'emergency' THEN 1
      WHEN 'critical' THEN 2
      WHEN 'warning' THEN 3
      ELSE 4
    END,
    r.created_at DESC;
END;
$$ LANGUAGE plpgsql STABLE;

COMMENT ON FUNCTION ml.get_active_risk_events(UUID) IS
'Returns all unresolved risk events, optionally filtered by user.

Parameters:
  - p_user_id: User ID to filter by (NULL for all events including system-wide)

Returns events ordered by severity (emergency first) then by time.

Example usage:
  SELECT * FROM ml.get_active_risk_events();
  SELECT * FROM ml.get_active_risk_events(''550e8400-e29b-41d4-a716-446655440000'');
';


-- -----------------------------------------------------
-- Function: ml.check_circuit_breaker_status
-- -----------------------------------------------------
-- Checks if circuit breaker is active for a user
-- -----------------------------------------------------

CREATE OR REPLACE FUNCTION ml.check_circuit_breaker_status(
  p_user_id UUID DEFAULT NULL
)
RETURNS TABLE(
  is_active BOOLEAN,
  event_id UUID,
  trigger_reason TEXT,
  created_at TIMESTAMPTZ,
  details JSONB
) AS $$
BEGIN
  RETURN QUERY
  SELECT
    TRUE AS is_active,
    r.id AS event_id,
    r.details->>'trigger_reason' AS trigger_reason,
    r.created_at,
    r.details
  FROM ml.risk_events r
  WHERE r.event_type = 'CIRCUIT_BREAKER'
    AND r.resolved = FALSE
    AND (p_user_id IS NULL OR r.user_id = p_user_id OR r.user_id IS NULL)
  ORDER BY r.created_at DESC
  LIMIT 1;

  -- If no rows returned, return false status
  IF NOT FOUND THEN
    RETURN QUERY SELECT FALSE, NULL::UUID, NULL::TEXT, NULL::TIMESTAMPTZ, NULL::JSONB;
  END IF;
END;
$$ LANGUAGE plpgsql STABLE;

COMMENT ON FUNCTION ml.check_circuit_breaker_status(UUID) IS
'Checks if circuit breaker is currently active for a user.

Returns:
  - is_active: TRUE if circuit breaker is engaged
  - event_id: ID of the active circuit breaker event
  - trigger_reason: Reason the circuit breaker was triggered
  - created_at: When the circuit breaker was activated
  - details: Full details of the event

Example usage:
  SELECT * FROM ml.check_circuit_breaker_status();
  SELECT is_active FROM ml.check_circuit_breaker_status(''550e8400-e29b-41d4-a716-446655440000'');
';
