// API envelope (before unwrapping)
export interface APIEnvelope<T = unknown> {
  status: 'success' | 'error';
  data: T | null;
  error: string | null;
}

// Auth
export interface TokenResponse {
  access_token: string;
  token_type: string;
}

// Watchlist
export interface WatchlistEntry {
  symbol: string;
  entry_type: 'auto' | 'manual';
  composite_score: number | null;
  dimensions: DimensionScore[];
  rr_ratio: number | null;
  rr_direction: string | null;
  momentum_percentile: number | null;
  strategy_rank: number | null;
  sr_levels: SRLevelSummary[];
  last_close: number | null;
  change_pct: number | null;
  price_date: string | null;
  added_at: string;
}

export interface DimensionScore {
  dimension: string;
  score: number;
}

export interface SRLevelSummary {
  price_level: number;
  type: 'support' | 'resistance';
  strength: number;
}

// S/R Zone
export interface SRZone {
  low: number;
  high: number;
  midpoint: number;
  strength: number;
  type: 'support' | 'resistance';
  level_count: number;
}

// OHLCV
export interface OHLCVBar {
  id: number;
  ticker_id: number;
  date: string;
  open: number;
  high: number;
  low: number;
  close: number;
  volume: number;
  created_at: string;
}

// Scores
export interface SubScore {
  name: string;
  score: number;
  weight: number;
  raw_value: number | string | null;
  description: string;
}

export interface ScoreBreakdown {
  sub_scores: SubScore[];
  formula: string;
  unavailable: { name: string; reason: string }[];
}

export interface CompositeBreakdown {
  weights: Record<string, number>;
  available_dimensions: string[];
  missing_dimensions: string[];
  renormalized_weights: Record<string, number>;
  formula: string;
  base_score?: number | null;
  sentiment_score?: number | null;
  sentiment_adjustment?: number | null;
  max_sentiment_adjustment?: number | null;
}

export interface ScoreResponse {
  symbol: string;
  composite_score: number | null;
  composite_stale: boolean;
  weights: Record<string, number>;
  dimensions: DimensionScoreDetail[];
  missing_dimensions: string[];
  computed_at: string | null;
  composite_breakdown?: CompositeBreakdown | null;
}

export interface DimensionScoreDetail {
  dimension: string;
  score: number;
  is_stale: boolean;
  computed_at: string | null;
  breakdown?: ScoreBreakdown | null;
}

export interface RankingEntry {
  symbol: string;
  composite_score: number;
  composite_stale: boolean;
  dimensions: DimensionScoreDetail[];
}

export interface RankingsResponse {
  rankings: RankingEntry[];
  weights: Record<string, number>;
}

// Trade Setups
export interface TradeSetup {
  id: number;
  symbol: string;
  direction: string;
  entry_price: number;
  stop_loss: number;
  target: number;
  rr_ratio: number;
  composite_score: number;
  detected_at: string;
  confidence_score: number | null;
  targets: TradeTarget[];
  conflict_flags: string[];
  recommended_action: 'LONG_HIGH' | 'LONG_MODERATE' | 'SHORT_HIGH' | 'SHORT_MODERATE' | 'NEUTRAL' | null;
  reasoning: string | null;
  risk_level: 'Low' | 'Medium' | 'High' | null;
  actual_outcome: string | null;
  outcome_date: string | null;
  evaluated_at: string | null;
  current_price: number | null;
  momentum_percentile?: number | null;
  strategy_rank?: number | null;
  volatility_percentile?: number | null;
  context_as_of?: TradeSetupContextAsOf | null;
  recommendation_summary?: RecommendationSummary;
}

export interface TradeSetupContextAsOf {
  setup_detected_at: string;
  score_computed_at: string | null;
  sentiment_at: string | null;
  price_date: string | null;
  price_updated_at: string | null;
}

// Performance / outcome statistics
export interface OutcomeBucketStats {
  total: number;
  wins: number;
  losses: number;
  expired: number;
  hit_rate: number | null;
  avg_r: number | null;
  total_r: number | null;
}

export interface PerformanceStats {
  overall: OutcomeBucketStats;
  pending: number;
  maturing: number;
  by_direction: Record<string, OutcomeBucketStats>;
  by_action: Record<string, OutcomeBucketStats>;
  by_confidence: Record<string, OutcomeBucketStats>;
}

// Activation gate: what counts as an actionable signal
export interface ActivationConfig {
  min_momentum_percentile: number;
  min_rr: number;
  min_confidence: number;
  require_high_conviction: boolean;
  exclude_conflicts: boolean;
  exclude_neutral: boolean;
}

// Cron schedule for the daily/intraday pipelines + fundamentals
export interface ScheduleConfig {
  schedule_timezone: string;
  schedule_daily_pipeline_cron: string;
  schedule_intraday_pipeline_cron: string;
  schedule_fundamentals_cron: string;
}

// Runtime sentiment LLM configuration
export interface SentimentProviderConfig {
  provider: string;
  model: string;
  base_url: string;
  api_key_configured: boolean;
  api_key_source: 'database' | 'environment' | 'none';
  web_search: boolean;
  valid_providers: string[];
  default_models: Record<string, string>;
  web_search_providers: string[];
  custom_base_url_providers: string[];
}

export interface PaperTrade {
  id: number;
  symbol: string;
  direction: 'long' | 'short';
  entry_price: number;
  shares: number;
  stop_loss: number;
  target: number;
  status: 'open' | 'closed';
  opened_at: string;
  close_price: number | null;
  closed_at: string | null;
  current_price: number | null;
  benchmark_return_pct: number | null;
  alpha_pct: number | null;
  alpha_usd: number | null;
  close_reason: 'time' | 'trailing' | 'stop' | 'target' | 'manual' | null;
  trailing_stop: number | null;
  trailing_distance_pct: number | null;
}

export interface ExitPolicy {
  mode: 'time' | 'trailing' | 'atr_trailing' | 'target';
  trailing_pct: number;
  atr_multiplier: number;
  hold_days: number;
}

export interface BacktestBucket {
  total: number;
  wins: number;
  losses: number;
  expired: number;
  hit_rate: number | null;
  avg_r: number | null;
  total_r: number | null;
  // Net of transaction costs — optional so a stale cached report still renders.
  net_avg_r?: number | null;
  net_total_r?: number | null;
  best_r?: number | null;
  worst_r?: number | null;
  avg_hold_days?: number | null;
  net_r_per_day?: number | null;
  // Robustness: distribution shape, and expectancy without the top winners.
  median_net_r?: number | null;
  profit_factor?: number | null;
  net_avg_r_ex_top5?: number | null;
}

export interface BacktestSweepRow extends BacktestBucket {
  min_momentum_percentile: number;
}

export interface BacktestTimeExitRow {
  hold_days: number;
  total: number;
  wins: number;
  win_rate: number | null;
  avg_r: number | null;
  total_r: number | null;
  net_avg_r?: number | null;
  net_total_r?: number | null;
  best_r?: number | null;
  worst_r?: number | null;
  avg_hold_days?: number | null;
  net_r_per_day?: number | null;
  median_net_r?: number | null;
  profit_factor?: number | null;
  net_avg_r_ex_top5?: number | null;
}

export interface BacktestPortfolioPolicy {
  policy?: string;
  starting_capital: number;
  final_equity: number;
  total_return_pct: number;
  cagr_pct: number | null;
  max_drawdown_pct: number;
  sharpe: number | null;
  trades: number;
  win_rate: number | null;
  avg_trade_pnl: number | null;
  best_trade_r: number | null;
  worst_trade_r: number | null;
  best_trade_pnl: number | null;
  worst_trade_pnl: number | null;
  avg_hold_days: number | null;
  skipped_book_full: number;
  spy_return_pct: number | null;
  yearly_returns?: { year: number; return_pct: number | null }[];
  exit_reasons?: Record<string, number>;
  equity_curve?: BacktestCurvePoint[];
  benchmark_curve?: BacktestCurvePoint[];
  start_date: string;
  end_date: string;
}

export interface BacktestCurvePoint {
  date: string;
  equity: number;
  return_pct: number | null;
}

export interface BacktestRecommendation {
  headline: string | null;
  items: { topic: string; text: string }[];
  note?: string;
}

export interface BacktestResearchRecommendation {
  items: { topic: string; text: string; candidate?: boolean }[];
  note?: string;
}

export interface BacktestPortfolioSim {
  params: {
    starting_capital: number;
    max_positions: number;
    risk_per_trade_pct: number;
    notional_cap_pct: number;
    cost_per_side_pct: number;
    hold_days: number;
  };
  policies: BacktestPortfolioPolicy[];
  note?: string;
}

export interface BacktestStrategyVariant extends BacktestPortfolioPolicy {
  variant: string;
  label: string;
  ranking: 'raw' | 'residual' | string;
  cutoff: number;
  max_positions: number;
  risk_per_trade_pct: number;
  risk_scale: string | null;
}

export interface BacktestStrategyVariants {
  variants: BacktestStrategyVariant[];
  note?: string;
}

export interface BacktestPortfolioMonitorRun extends BacktestPortfolioPolicy {
  strategy: string;
  label: string;
  description: string;
  is_production: boolean;
  entry_variant: string;
  exit_policy: string;
  lookback: string;
  lookback_label: string;
}

export interface BacktestPortfolioMonitor {
  production_strategy: string;
  strategies: { strategy: string; label: string; description: string; is_production: boolean }[];
  lookbacks: { lookback: string; label: string }[];
  runs: BacktestPortfolioMonitorRun[];
  note?: string;
}

export interface BacktestGateAblationRow extends BacktestBucket {
  variant: string;
  // The same variant graded under the hold-to-horizon time exit.
  hold_days?: number;
  hold_avg_r?: number | null;
  hold_net_avg_r?: number | null;
  hold_total_r?: number | null;
}

export interface BacktestSignalEvalRow {
  signal: string;
  weeks: number;
  avg_cross_section: number | null;
  mean_ic: number;
  ic_t_stat: number | null;
  ic_positive_pct: number;
  mean_quintile_spread: number | null;
  reliable: boolean;
}

export interface BacktestReport {
  generated_at: string;
  tickers: number;
  candidates: number;
  qualified: number;
  params: {
    step_days: number;
    horizon_days: number;
    min_lookback: number;
    cost_per_side_pct?: number;
    target_model?: 'production_gtl' | 'structural_sr';
    target_model_label?: string;
    is_production_target_model?: boolean;
  };
  overall_qualified: BacktestBucket;
  overall_all: BacktestBucket;
  by_direction: Record<string, BacktestBucket>;
  min_momentum_percentile: number;
  sweep: BacktestSweepRow[];
  gate_ablation?: BacktestGateAblationRow[];
  gate_ablation_note?: string;
  time_exit_sweep?: BacktestTimeExitRow[];
  portfolio_sim?: BacktestPortfolioSim;
  strategy_variants?: BacktestStrategyVariants;
  exit_policy_variants?: { variants: BacktestStrategyVariant[]; note?: string };
  portfolio_monitor?: BacktestPortfolioMonitor | null;
  recommendation?: BacktestRecommendation;
  research_recommendation?: BacktestResearchRecommendation;
  signal_eval?: BacktestSignalEvalRow[];
  signal_eval_note?: string;
  note: string;
}

export interface MarketRegime {
  label: 'bullish' | 'bearish' | 'neutral' | 'unknown';
  benchmark?: string;
  price?: number | null;
  sma50?: number | null;
  sma200?: number | null;
  pct_above_200?: number | null;
  reason?: string | null;
  computed_at?: string;
}

// AI/Tech Regime-Change Monitor (standalone, observational)
export type RegimeBand = 'stable' | 'watch' | 'elevated' | 'breaking';

export interface RegimeSignal {
  id: string;
  label: string;
  sub_score: number | null;
  weight: number;
  available: boolean;
  contribution: number;
}

export interface RegimeSubScore {
  score: number | null;
  band: RegimeBand | null;
  delta_7?: number | null;
  delta_30?: number | null;
}

export interface RegimeHistoryPoint {
  date: string;
  index: number;
  early_warning: number | null;
  combined: number | null;
}

export interface RegimeMonitor {
  available: boolean;
  reason?: string;
  date?: string;
  total_score?: number;
  band?: RegimeBand;
  alert_threshold?: number;
  breakdown?: RegimeSignal[];
  inputs?: {
    vix: number | null;
    hy_oas: number | null;
    fundamentals_fetched_at: string | null;
  };
  trend?: { delta_7: number | null; delta_30: number | null };
  // Separate, observational early-warning score (breadth divergence) + a small
  // combined blend. Decoupled from the index above.
  early_warning?: RegimeSubScore;
  combined?: RegimeSubScore;
}

export interface RegimeFundamentals {
  f1_score: number;
  f3_score: number;
  locked: boolean;
  reasoning: string | null;
  fetched_at: string | null;
  source: string;
  capex?: Record<string, string>;
  good_news_stock_down?: string | null;
}

export interface RegimeConfig {
  weights: Record<string, number>;
  alert_threshold: number;
  tickers: Record<string, unknown>;
  leader_weight: number;
  rs_lookback: number;
  fundamental_staleness_days: number;
}

// Event study — measured lead time of early-warning indicators vs. drawdowns
export interface EventStudyLeadStats {
  median_lead_days: number | null;
  events_with_signal: number;
  events_total: number;
  warn_threshold: number;
  mean_path: { rel_day: number; value: number }[];
  signal: {
    base_rate: number;
    horizon_days: number;
    rows: { threshold: number; precision: number | null; recall: number | null; alarms: number }[];
  };
}

export interface EventStudyPerEvent {
  date: string;
  depth_pct: number;
  breadth_lead: number | null;
  coincident_lead: number | null;
}

export interface EventStudyReport {
  available: boolean;
  reason?: string;
  generated_at?: string;
  params?: {
    benchmark: string;
    event_threshold_pct: number;
    cooldown_days: number;
    horizon_days: number;
    warn_percentile: number;
  };
  events?: { date: string; index: number; depth_pct: number }[];
  indicators?: {
    breadth_divergence: EventStudyLeadStats;
    coincident_price: EventStudyLeadStats;
  };
  per_event?: EventStudyPerEvent[];
  lead_delta_days?: number | null;
  recent_breadth?: { date: string; breadth: number; divergence: number | null }[];
}

export interface AlertConfig {
  enabled: boolean;
  telegram_chat_id: string;
  bot_token_configured: boolean;
  bot_token_source: 'database' | 'environment' | 'none';
  qualified_enabled: boolean;
  sr_proximity_enabled: boolean;
  score_drop_enabled: boolean;
  digest_enabled: boolean;
  regime_quadrant_enabled: boolean;
  trade_closed_enabled: boolean;
}

export interface AlertTestResult {
  ok: boolean;
  error?: string;
}

export interface SentimentTestResult {
  ok: boolean;
  provider: string;
  model: string;
  ticker?: string;
  classification?: string;
  confidence?: number;
  reasoning?: string | null;
  error?: string;
}

export interface TradeTarget {
  price: number;
  distance_from_entry: number;
  distance_atr_multiple: number;
  rr_ratio: number;
  probability: number;
  classification: 'Conservative' | 'Moderate' | 'Aggressive';
  sr_level_id: number;
  sr_strength: number;
  is_primary?: boolean;
}

export interface RecommendationSummary {
  action: string;
  reasoning: string | null;
  risk_level: 'Low' | 'Medium' | 'High' | null;
  composite_score: number;
}

// S/R Levels
export interface SRLevel {
  id: number;
  price_level: number;
  type: 'support' | 'resistance';
  strength: number;
  detection_method: string;
  created_at: string;
}

export interface SRLevelResponse {
  symbol: string;
  levels: SRLevel[];
  zones: SRZone[];
  visible_levels: SRLevel[];
  count: number;
}

export interface GateTargetLevel {
  price_level: number;
  type: 'support' | 'resistance';
  strength: number;
  detection_method: string;
  sources: string[];
  traffic_count: number;
}

export interface GateTargetLadderResponse {
  symbol: string;
  levels: GateTargetLevel[];
  count: number;
  lookback_bars: number;
}

// Sentiment
export interface CitationItem {
  url: string;
  title: string;
}

export interface SentimentScore {
  id: number;
  classification: 'bullish' | 'bearish' | 'neutral';
  confidence: number;
  source: string;
  timestamp: string;
  reasoning: string;
  citations: CitationItem[];
  recommendation: 'buy' | 'hold' | 'avoid' | null;
}

export interface SentimentResponse {
  symbol: string;
  scores: SentimentScore[];
  count: number;
  dimension_score: number | null;
  lookback_hours: number;
}

// Fundamentals
export interface FundamentalResponse {
  symbol: string;
  pe_ratio: number | null;
  revenue_growth: number | null;
  earnings_surprise: number | null;
  market_cap: number | null;
  next_earnings_date: string | null;
  fetched_at: string | null;
  unavailable_fields: Record<string, string>;
}

// Indicators
export interface IndicatorResult {
  indicator_type: string;
  values: Record<string, unknown>;
  score: number;
  bars_used: number;
}

export interface EMACrossResult {
  short_ema: number;
  long_ema: number;
  short_period: number;
  long_period: number;
  signal: 'bullish' | 'bearish' | 'neutral';
}

// Tickers
export interface Ticker {
  id: number;
  symbol: string;
  name: string | null;
  created_at: string;
}

// Admin
export interface AdminUser {
  id: number;
  username: string;
  role: string;
  has_access: boolean;
  created_at: string | null;
  updated_at: string | null;
}

export interface SystemSetting {
  key: string;
  value: string;
  updated_at: string | null;
}

export interface RecommendationConfig {
  high_confidence_threshold: number;
  moderate_confidence_threshold: number;
  confidence_diff_threshold: number;
  signal_alignment_weight: number;
  sr_strength_weight: number;
  momentum_technical_divergence_threshold: number;
  fundamental_technical_divergence_threshold: number;
}

export type TickerUniverse = 'sp500' | 'nasdaq100' | 'nasdaq_all';

export interface TickerUniverseSetting {
  universe: TickerUniverse;
}

export interface TickerUniverseBootstrapResult {
  universe: TickerUniverse;
  total_universe_symbols: number;
  added: number;
  already_tracked: number;
  deleted: number;
}

export interface PipelineReadiness {
  symbol: string;
  ohlcv_bars: number;
  ohlcv_last_date: string | null;
  dimensions: {
    technical: number | null;
    sr_quality: number | null;
    sentiment: number | null;
    fundamental: number | null;
    momentum: number | null;
  };
  sentiment_count: number;
  sentiment_last_at: string | null;
  has_fundamentals: boolean;
  fundamentals_fetched_at: string | null;
  sr_level_count: number;
  has_composite: boolean;
  composite_stale: boolean | null;
  trade_setup_count: number;
  missing_reasons: string[];
  ready_for_scanner: boolean;
}
