import { supabase } from '../db.js';
import { OptionsFlowQuery } from './optionsFlowQuery.js';

/**
 * Scanner Query Module
 * Handles multi-signal scanning queries
 */

export class ScannerQuery {
  /**
   * Scan for multi-signal opportunities
   * @param {Object} criteria - Scan criteria
   * @returns {Promise<Array>} Matching opportunities
   */
  static async scanMultiSignal(criteria = {}) {
    const {
      minRocketScore = 60,
      minAlignment = 70,
      minPremium = 50000,
      symbols = null,
      timeWindow = 60, // minutes
      requireBadges = ['🚀'],
      maxResults = 50
    } = criteria;
    
    // Calculate start time
    const startTime = new Date();
    startTime.setMinutes(startTime.getMinutes() - timeWindow);
    
    // Get recent flows
    const flows = await OptionsFlowQuery.getRecentFlow({
      minPremium,
      startDate: startTime.toISOString(),
      limit: 1000
    });
    
    // Filter by symbols if provided
    let filteredFlows = flows;
    if (symbols && Array.isArray(symbols) && symbols.length > 0) {
      const symbolSet = new Set(symbols.map(s => s.toUpperCase()));
      filteredFlows = flows.filter(f => symbolSet.has(f.symbol?.toUpperCase()));
    }
    
    // Filter by rocket score if available
    if (minRocketScore) {
      filteredFlows = filteredFlows.filter(f => {
        const score = f.rocket_score || f.rocketScore?.score || 0;
        return score >= minRocketScore;
      });
    }
    
    // Sort by score and limit results
    filteredFlows.sort((a, b) => {
      const scoreA = a.rocket_score || a.rocketScore?.score || 0;
      const scoreB = b.rocket_score || b.rocketScore?.score || 0;
      return scoreB - scoreA;
    });
    
    return filteredFlows.slice(0, maxResults);
  }
  
  /**
   * Scan for institutional clusters
   * @param {Object} criteria - Cluster scan criteria
   * @returns {Promise<Array>} Detected clusters
   */
  static async scanClusters(criteria = {}) {
    const {
      minClusterSize = 3,
      timeWindow = 15, // minutes
      minTotalPremium = 100000,
      symbols = null
    } = criteria;
    
    const startTime = new Date();
    startTime.setMinutes(startTime.getMinutes() - timeWindow * 2);
    
    const flows = await OptionsFlowQuery.getRecentFlow({
      startDate: startTime.toISOString(),
      limit: 1000
    });
    
    // Group by symbol
    const bySymbol = {};
    flows.forEach(flow => {
      const symbol = flow.symbol?.toUpperCase();
      if (!symbol) return;
      
      if (!bySymbol[symbol]) {
        bySymbol[symbol] = [];
      }
      bySymbol[symbol].push(flow);
    });
    
    // Filter by symbols if provided
    let symbolsToCheck = Object.keys(bySymbol);
    if (symbols && Array.isArray(symbols) && symbols.length > 0) {
      const symbolSet = new Set(symbols.map(s => s.toUpperCase()));
      symbolsToCheck = symbolsToCheck.filter(s => symbolSet.has(s));
    }
    
    // Detect clusters per symbol
    const clusters = [];
    symbolsToCheck.forEach(symbol => {
      const symbolFlows = bySymbol[symbol].sort((a, b) => {
        const timeA = new Date(a.created_at || a.timestamp || 0);
        const timeB = new Date(b.created_at || b.timestamp || 0);
        return timeA - timeB;
      });
      
      // Simple cluster detection: consecutive flows within time window
      let currentCluster = [];
      let clusterStartTime = null;
      
      symbolFlows.forEach(flow => {
        const flowTime = new Date(flow.created_at || flow.timestamp);
        
        if (clusterStartTime === null) {
          clusterStartTime = flowTime;
          currentCluster = [flow];
        } else {
          const timeDiff = (flowTime - clusterStartTime) / (1000 * 60);
          
          if (timeDiff <= timeWindow) {
            currentCluster.push(flow);
          } else {
            // Save cluster if it meets criteria
            if (currentCluster.length >= minClusterSize) {
              const totalPremium = currentCluster.reduce(
                (sum, f) => sum + (f.total_premium || 0),
                0
              );
              
              if (totalPremium >= minTotalPremium) {
                clusters.push({
                  symbol,
                  flows: currentCluster,
                  size: currentCluster.length,
                  totalPremium,
                  startTime: clusterStartTime,
                  endTime: new Date(currentCluster[currentCluster.length - 1].created_at || currentCluster[currentCluster.length - 1].timestamp)
                });
              }
            }
            
            // Start new cluster
            clusterStartTime = flowTime;
            currentCluster = [flow];
          }
        }
      });
      
      // Check last cluster
      if (currentCluster.length >= minClusterSize) {
        const totalPremium = currentCluster.reduce(
          (sum, f) => sum + (f.total_premium || 0),
          0
        );
        
        if (totalPremium >= minTotalPremium) {
          clusters.push({
            symbol,
            flows: currentCluster,
            size: currentCluster.length,
            totalPremium,
            startTime: clusterStartTime,
            endTime: new Date(currentCluster[currentCluster.length - 1].created_at || currentCluster[currentCluster.length - 1].timestamp)
          });
        }
      }
    });
    
    // Sort by total premium
    clusters.sort((a, b) => b.totalPremium - a.totalPremium);
    
    return clusters;
  }
  
  /**
   * Scan for alert correlations
   * @param {Array} alerts - Array of alerts
   * @param {Object} criteria - Correlation criteria
   * @returns {Promise<Array>} Correlated opportunities
   */
  static async scanAlertCorrelations(alerts, criteria = {}) {
    const {
      timeWindow = 30, // minutes
      minConfidence = 0.7
    } = criteria;
    
    if (!alerts || alerts.length === 0) {
      return [];
    }
    
    // Extract symbols from alerts
    const alertSymbols = alerts
      .map(a => a.symbol?.toUpperCase())
      .filter(Boolean);
    
    if (alertSymbols.length === 0) {
      return [];
    }
    
    // Get recent flows for alert symbols
    const startTime = new Date();
    startTime.setMinutes(startTime.getMinutes() - timeWindow);
    
    const flows = await OptionsFlowQuery.getRecentFlow({
      startDate: startTime.toISOString(),
      limit: 500
    });
    
    // Filter flows matching alert symbols
    const symbolSet = new Set(alertSymbols);
    const correlatedFlows = flows.filter(f => 
      symbolSet.has(f.symbol?.toUpperCase())
    );
    
    // Group by symbol and calculate correlation score
    const correlations = {};
    correlatedFlows.forEach(flow => {
      const symbol = flow.symbol?.toUpperCase();
      if (!correlations[symbol]) {
        correlations[symbol] = {
          symbol,
          flows: [],
          alertCount: alertSymbols.filter(s => s === symbol).length,
          totalPremium: 0,
          avgRocketScore: 0
        };
      }
      
      correlations[symbol].flows.push(flow);
      correlations[symbol].totalPremium += (flow.total_premium || 0);
    });
    
    // Calculate correlation scores
    const results = Object.values(correlations).map(corr => {
      const scores = corr.flows.map(f => 
        f.rocket_score || f.rocketScore?.score || 0
      );
      corr.avgRocketScore = scores.length > 0
        ? scores.reduce((a, b) => a + b, 0) / scores.length
        : 0;
      
      // Correlation confidence based on alert count and flow quality
      corr.confidence = Math.min(1.0, 
        (corr.alertCount * 0.3) + 
        (Math.min(corr.avgRocketScore / 100, 0.5)) +
        (Math.min(corr.totalPremium / 500000, 0.2))
      );
      
      return corr;
    }).filter(c => c.confidence >= minConfidence)
      .sort((a, b) => b.confidence - a.confidence);
    
    return results;
  }
}

