/**
 * ML Overlay Controller
 * Handles chart overlay endpoints for trading visualization
 */

import { Request, Response, NextFunction } from 'express';
import { mlOverlayService, OverlayConfig } from '../services/ml-overlay.service';

// ============================================================================
// Overlay Endpoints
// ============================================================================

/**
 * Get complete chart overlay for a symbol
 */
export async function getChartOverlay(
  req: Request,
  res: Response,
  next: NextFunction
): Promise<void> {
  try {
    const { symbol } = req.params;
    const config = parseOverlayConfig(req.query);

    const overlay = await mlOverlayService.getChartOverlay(symbol.toUpperCase(), config);

    res.json({
      success: true,
      data: overlay,
    });
  } catch (error) {
    next(error);
  }
}

/**
 * Get overlays for multiple symbols
 */
export async function getBatchOverlays(
  req: Request,
  res: Response,
  next: NextFunction
): Promise<void> {
  try {
    const { symbols } = req.body;
    const config = parseOverlayConfig(req.body);

    if (!symbols || !Array.isArray(symbols) || symbols.length === 0) {
      res.status(400).json({
        success: false,
        error: { message: 'Symbols array is required', code: 'VALIDATION_ERROR' },
      });
      return;
    }

    if (symbols.length > 20) {
      res.status(400).json({
        success: false,
        error: { message: 'Maximum 20 symbols allowed per request', code: 'VALIDATION_ERROR' },
      });
      return;
    }

    const overlays = await mlOverlayService.getBatchOverlays(
      symbols.map((s: string) => s.toUpperCase()),
      config
    );

    // Convert Map to object for JSON response
    const result: Record<string, unknown> = {};
    overlays.forEach((value, key) => {
      result[key] = value;
    });

    res.json({
      success: true,
      data: result,
    });
  } catch (error) {
    next(error);
  }
}

/**
 * Get price levels only
 */
export async function getPriceLevels(
  req: Request,
  res: Response,
  next: NextFunction
): Promise<void> {
  try {
    const { symbol } = req.params;

    const levels = await mlOverlayService.getPriceLevels(symbol.toUpperCase());

    res.json({
      success: true,
      data: {
        symbol: symbol.toUpperCase(),
        levels,
        timestamp: new Date().toISOString(),
      },
    });
  } catch (error) {
    next(error);
  }
}

/**
 * Get signal markers
 */
export async function getSignalMarkers(
  req: Request,
  res: Response,
  next: NextFunction
): Promise<void> {
  try {
    const { symbol } = req.params;
    const limit = Math.min(Number(req.query.limit) || 20, 100);

    const markers = await mlOverlayService.getSignalMarkers(symbol.toUpperCase(), limit);

    res.json({
      success: true,
      data: {
        symbol: symbol.toUpperCase(),
        markers,
        timestamp: new Date().toISOString(),
      },
    });
  } catch (error) {
    next(error);
  }
}

/**
 * Get AMD phase overlay
 */
export async function getAMDPhaseOverlay(
  req: Request,
  res: Response,
  next: NextFunction
): Promise<void> {
  try {
    const { symbol } = req.params;

    const amdPhase = await mlOverlayService.getAMDPhaseOverlay(symbol.toUpperCase());

    res.json({
      success: true,
      data: {
        symbol: symbol.toUpperCase(),
        ...amdPhase,
        timestamp: new Date().toISOString(),
      },
    });
  } catch (error) {
    next(error);
  }
}

/**
 * Get prediction bands
 */
export async function getPredictionBands(
  req: Request,
  res: Response,
  next: NextFunction
): Promise<void> {
  try {
    const { symbol } = req.params;
    const horizonMinutes = Math.min(Number(req.query.horizon) || 90, 480);
    const intervals = Math.min(Number(req.query.intervals) || 10, 50);

    const bands = await mlOverlayService.getPredictionBands(
      symbol.toUpperCase(),
      horizonMinutes,
      intervals
    );

    res.json({
      success: true,
      data: {
        symbol: symbol.toUpperCase(),
        horizonMinutes,
        bands,
        timestamp: new Date().toISOString(),
      },
    });
  } catch (error) {
    next(error);
  }
}

/**
 * Clear overlay cache
 */
export async function clearCache(
  req: Request,
  res: Response,
  next: NextFunction
): Promise<void> {
  try {
    const { symbol } = req.params;

    mlOverlayService.clearCache(symbol?.toUpperCase());

    res.json({
      success: true,
      message: symbol ? `Cache cleared for ${symbol.toUpperCase()}` : 'All cache cleared',
    });
  } catch (error) {
    next(error);
  }
}

// ============================================================================
// Helper Functions
// ============================================================================

function parseOverlayConfig(query: Record<string, unknown>): Partial<OverlayConfig> {
  const config: Partial<OverlayConfig> = {};

  if (query.showPriceLevels !== undefined) {
    config.showPriceLevels = query.showPriceLevels === 'true' || query.showPriceLevels === true;
  }
  if (query.showTrendLines !== undefined) {
    config.showTrendLines = query.showTrendLines === 'true' || query.showTrendLines === true;
  }
  if (query.showSignalMarkers !== undefined) {
    config.showSignalMarkers = query.showSignalMarkers === 'true' || query.showSignalMarkers === true;
  }
  if (query.showZones !== undefined) {
    config.showZones = query.showZones === 'true' || query.showZones === true;
  }
  if (query.showPredictionBands !== undefined) {
    config.showPredictionBands = query.showPredictionBands === 'true' || query.showPredictionBands === true;
  }
  if (query.showIndicators !== undefined) {
    config.showIndicators = query.showIndicators === 'true' || query.showIndicators === true;
  }
  if (query.showAMDPhase !== undefined) {
    config.showAMDPhase = query.showAMDPhase === 'true' || query.showAMDPhase === true;
  }

  return config;
}
