/**
 * Message Formatters & Signal Parsers
 * Utility functions for parsing assistant responses and formatting trading data
 */

import type { TradingSignal } from '../components/SignalCard';
import type { ToolCall } from '../components/ToolCallCard';

// Types
export interface PriceLevel {
  price: number;
  type: 'entry' | 'stop_loss' | 'take_profit' | 'support' | 'resistance' | 'unknown';
  label?: string;
}

export interface ToolCallReference {
  toolName: string;
  status: 'pending' | 'running' | 'success' | 'error';
  position: { start: number; end: number };
}

export interface ParsedSignal {
  symbol: string;
  direction: 'BUY' | 'SELL' | 'HOLD';
  entry?: number;
  stopLoss?: number;
  takeProfit?: number;
  confidence?: number;
  timeframe?: string;
  raw: string;
}

// ============================================================
// Price & Number Formatting
// ============================================================

/**
 * Format price based on symbol type
 */
export function formatPrice(price: number, symbol: string): string {
  const isJpy = symbol.toUpperCase().includes('JPY');
  const decimals = isJpy ? 3 : 5;
  return price.toFixed(decimals);
}

/**
 * Format percentage with optional decimals
 */
export function formatPercentage(value: number, decimals = 2): string {
  const sign = value >= 0 ? '+' : '';
  return `${sign}${value.toFixed(decimals)}%`;
}

/**
 * Format P&L with value and percentage
 */
export function formatPnL(pnl: number, pnlPct?: number): string {
  const sign = pnl >= 0 ? '+' : '';
  const pnlStr = `${sign}$${Math.abs(pnl).toFixed(2)}`;

  if (pnlPct !== undefined) {
    return `${pnlStr} (${formatPercentage(pnlPct)})`;
  }
  return pnlStr;
}

/**
 * Format volume/lots
 */
export function formatVolume(volume: number): string {
  if (volume >= 1) return volume.toFixed(2);
  return volume.toFixed(3);
}

/**
 * Format pips difference
 */
export function formatPips(pips: number): string {
  const sign = pips >= 0 ? '+' : '';
  return `${sign}${pips.toFixed(1)} pips`;
}

/**
 * Format currency
 */
export function formatCurrency(value: number, currency = 'USD'): string {
  return new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency,
    minimumFractionDigits: 2,
  }).format(value);
}

// ============================================================
// Signal Parsing
// ============================================================

/**
 * Extract trading signals from assistant response text
 */
export function extractTradingSignals(content: string): ParsedSignal[] {
  const signals: ParsedSignal[] = [];

  // Pattern for explicit signal mentions
  const signalPatterns = [
    // "BUY EURUSD at 1.0850"
    /\b(BUY|SELL)\s+([A-Z]{6})\s+(?:at\s+)?(\d+\.?\d*)/gi,
    // "Signal: LONG GBPUSD"
    /signal[:\s]+?(LONG|SHORT|BUY|SELL)\s+([A-Z]{6})/gi,
    // "Recommendation: Buy EUR/USD"
    /recommend(?:ation)?[:\s]+?(BUY|SELL)\s+([A-Z]{3})\/?([A-Z]{3})/gi,
  ];

  for (const pattern of signalPatterns) {
    let match;
    while ((match = pattern.exec(content)) !== null) {
      const direction = match[1].toUpperCase();
      const symbol = match[2] ? match[2].toUpperCase() : `${match[2]}${match[3]}`.toUpperCase();
      const entry = match[3] ? parseFloat(match[3]) : undefined;

      signals.push({
        symbol: symbol.replace('/', ''),
        direction: direction === 'LONG' ? 'BUY' : direction === 'SHORT' ? 'SELL' : direction as 'BUY' | 'SELL',
        entry,
        raw: match[0],
      });
    }
  }

  // Extract SL/TP if present near signal
  for (const signal of signals) {
    const slMatch = content.match(new RegExp(`SL[:\\s]*?(\\d+\\.\\d+)`, 'i'));
    const tpMatch = content.match(new RegExp(`TP[:\\s]*?(\\d+\\.\\d+)`, 'i'));
    const confMatch = content.match(/confidence[:\s]*?(\d+)%?/i);

    if (slMatch) signal.stopLoss = parseFloat(slMatch[1]);
    if (tpMatch) signal.takeProfit = parseFloat(tpMatch[1]);
    if (confMatch) signal.confidence = parseInt(confMatch[1]);
  }

  return signals;
}

/**
 * Extract price levels from text
 */
export function extractPriceLevels(content: string): PriceLevel[] {
  const levels: PriceLevel[] = [];

  const patterns = [
    { regex: /entry[:\s]*?(\d+\.?\d*)/gi, type: 'entry' as const },
    { regex: /stop[- ]?loss[:\s]*?(\d+\.?\d*)/gi, type: 'stop_loss' as const },
    { regex: /take[- ]?profit[:\s]*?(\d+\.?\d*)/gi, type: 'take_profit' as const },
    { regex: /support[:\s]*?(\d+\.?\d*)/gi, type: 'support' as const },
    { regex: /resistance[:\s]*?(\d+\.?\d*)/gi, type: 'resistance' as const },
    { regex: /SL[:\s]*?(\d+\.?\d*)/gi, type: 'stop_loss' as const },
    { regex: /TP[:\s]*?(\d+\.?\d*)/gi, type: 'take_profit' as const },
  ];

  for (const { regex, type } of patterns) {
    let match;
    while ((match = regex.exec(content)) !== null) {
      levels.push({
        price: parseFloat(match[1]),
        type,
      });
    }
  }

  return levels;
}

// ============================================================
// Tool Call Parsing
// ============================================================

/**
 * Parse tool call references from message content
 */
export function parseToolCallReferences(content: string): ToolCallReference[] {
  const references: ToolCallReference[] = [];

  // Pattern: [tool:get_price:running] or {tool:analyze_symbol:success}
  const pattern = /[\[{]tool:(\w+):(\w+)[\]}]/gi;

  let match;
  while ((match = pattern.exec(content)) !== null) {
    references.push({
      toolName: match[1],
      status: match[2] as ToolCallReference['status'],
      position: { start: match.index, end: match.index + match[0].length },
    });
  }

  return references;
}

/**
 * Extract tool names mentioned in text
 */
export function extractMentionedTools(content: string): string[] {
  const toolKeywords = [
    'get_price', 'get_quote', 'analyze_symbol', 'get_signal',
    'create_order', 'close_position', 'get_portfolio', 'search_symbols',
    'backtest', 'calculate_risk', 'get_history',
  ];

  return toolKeywords.filter((tool) =>
    content.toLowerCase().includes(tool.replace('_', ' ')) ||
    content.toLowerCase().includes(tool)
  );
}

// ============================================================
// Markdown & Text Processing
// ============================================================

/**
 * Parse markdown-style tables to structured data
 */
export function parseMarkdownTable(text: string): Record<string, string>[] {
  const lines = text.trim().split('\n');
  const data: Record<string, string>[] = [];

  // Find table header
  const headerLine = lines.findIndex((line) => line.includes('|'));
  if (headerLine === -1) return data;

  const headers = lines[headerLine]
    .split('|')
    .map((h) => h.trim())
    .filter(Boolean);

  // Skip separator line
  const dataStart = lines[headerLine + 1]?.includes('---') ? headerLine + 2 : headerLine + 1;

  for (let i = dataStart; i < lines.length; i++) {
    if (!lines[i].includes('|')) continue;

    const values = lines[i]
      .split('|')
      .map((v) => v.trim())
      .filter(Boolean);

    const row: Record<string, string> = {};
    headers.forEach((header, idx) => {
      row[header] = values[idx] || '';
    });
    data.push(row);
  }

  return data;
}

/**
 * Strip markdown formatting for plain text
 */
export function stripMarkdown(text: string): string {
  return text
    .replace(/\*\*(.*?)\*\*/g, '$1') // Bold
    .replace(/\*(.*?)\*/g, '$1') // Italic
    .replace(/`(.*?)`/g, '$1') // Inline code
    .replace(/```[\s\S]*?```/g, '') // Code blocks
    .replace(/\[(.*?)\]\(.*?\)/g, '$1') // Links
    .replace(/#{1,6}\s/g, '') // Headers
    .replace(/[>\-*+]\s/g, '') // List items
    .trim();
}

/**
 * Extract code blocks from markdown
 */
export function extractCodeBlocks(content: string): { language: string; code: string }[] {
  const blocks: { language: string; code: string }[] = [];
  const pattern = /```(\w*)\n([\s\S]*?)```/g;

  let match;
  while ((match = pattern.exec(content)) !== null) {
    blocks.push({
      language: match[1] || 'text',
      code: match[2].trim(),
    });
  }

  return blocks;
}

// ============================================================
// Time & Date Formatting
// ============================================================

/**
 * Format timestamp for chat display
 */
export function formatChatTime(timestamp: string | Date): string {
  const date = typeof timestamp === 'string' ? new Date(timestamp) : timestamp;
  const now = new Date();
  const diff = now.getTime() - date.getTime();

  // Less than a minute
  if (diff < 60000) return 'Just now';

  // Less than an hour
  if (diff < 3600000) {
    const mins = Math.floor(diff / 60000);
    return `${mins}m ago`;
  }

  // Same day
  if (date.toDateString() === now.toDateString()) {
    return date.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });
  }

  // Yesterday
  const yesterday = new Date(now);
  yesterday.setDate(yesterday.getDate() - 1);
  if (date.toDateString() === yesterday.toDateString()) {
    return 'Yesterday';
  }

  // Within a week
  if (diff < 7 * 24 * 3600000) {
    return date.toLocaleDateString('en-US', { weekday: 'short' });
  }

  // Older
  return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
}

/**
 * Format duration in ms to human readable
 */
export function formatDuration(ms: number): string {
  if (ms < 1000) return `${ms}ms`;
  if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
  return `${Math.floor(ms / 60000)}m ${Math.floor((ms % 60000) / 1000)}s`;
}

// ============================================================
// Validation Helpers
// ============================================================

/**
 * Check if text contains trading-related content
 */
export function containsTradingContent(content: string): boolean {
  const tradingKeywords = [
    'buy', 'sell', 'long', 'short', 'signal', 'entry', 'exit',
    'stop loss', 'take profit', 'sl', 'tp', 'pips', 'lots',
    'bullish', 'bearish', 'support', 'resistance', 'trend',
  ];

  const lowerContent = content.toLowerCase();
  return tradingKeywords.some((kw) => lowerContent.includes(kw));
}

/**
 * Validate price format for symbol
 */
export function isValidPrice(price: number, symbol: string): boolean {
  const isJpy = symbol.toUpperCase().includes('JPY');

  if (isJpy) {
    return price > 50 && price < 500; // JPY pairs typically 100-200
  }

  // Most forex pairs
  return price > 0.5 && price < 3;
}

// Export all formatters
export default {
  formatPrice,
  formatPercentage,
  formatPnL,
  formatVolume,
  formatPips,
  formatCurrency,
  extractTradingSignals,
  extractPriceLevels,
  parseToolCallReferences,
  extractMentionedTools,
  parseMarkdownTable,
  stripMarkdown,
  extractCodeBlocks,
  formatChatTime,
  formatDuration,
  containsTradingContent,
  isValidPrice,
};
