import type { AlertConditionDto } from '../../services/alertApi';
import type { ConditionGroupDto, StrategyRuleDto } from '../../services/strategyRuleApi';
import type { CandleUpdate } from '../../contexts/MultiChartMarketDataContext';
import { mapWsIndicatorsToChartFormat } from '../investmentChart/wsIndicatorMap';

/** 형광 비교용 — RealtimeChartValuesPopup과 동일 원칙 */
export function flashCompareTimeKeyMs(ts: number | undefined): string {
  if (ts == null || !Number.isFinite(ts)) return '—';
  const sec = ts > 1e12 ? Math.floor(ts / 1000) : Math.floor(ts);
  return `u:${sec}`;
}

export function flashCompareNumKey(v: unknown): string {
  if (v === null || v === undefined || v === '') return '—';
  const n = Number(v);
  if (!Number.isFinite(n)) return '—';
  return n.toLocaleString('en-US', {
    useGrouping: false,
    maximumFractionDigits: 12,
    minimumFractionDigits: 0,
  });
}

function formatDisplay(v: unknown): string {
  if (v === null || v === undefined || v === '') return '—';
  const n = Number(v);
  if (!Number.isFinite(n)) return '—';
  const abs = Math.abs(n);
  if (abs >= 1000) return n.toLocaleString(undefined, { maximumFractionDigits: 2 });
  if (abs >= 1) return n.toLocaleString(undefined, { maximumFractionDigits: 4 });
  if (abs >= 0.0001) return n.toLocaleString(undefined, { maximumFractionDigits: 6 });
  return n.toExponential(3);
}

export interface StrategyMetricColumn {
  id: string;
  label: string;
  getCompareValue: (raw: Record<string, number>, candle: CandleUpdate, mapped: Record<string, unknown>) => string;
  getDisplayValue: (raw: Record<string, number>, candle: CandleUpdate, mapped: Record<string, unknown>) => string;
}

function numFromRawOrMapped(
  raw: Record<string, number>,
  mapped: Record<string, unknown>,
  rawKeys: string[],
  mappedKeys: string[],
): number | null {
  for (const k of rawKeys) {
        const v = raw[k];
        if (v != null && Number.isFinite(Number(v))) return Number(v);
  }
  for (const k of mappedKeys) {
    const v = mapped[k];
    if (v != null && Number.isFinite(Number(v))) return Number(v);
  }
  return null;
}

function colFromNumber(
  id: string,
  label: string,
  rawKeys: string[],
  mappedKeys: string[],
): StrategyMetricColumn {
  return {
    id,
    label,
    getCompareValue: (raw, _c, mapped) => {
      const n = numFromRawOrMapped(raw, mapped, rawKeys, mappedKeys);
      return n == null ? '—' : flashCompareNumKey(n);
    },
    getDisplayValue: (raw, _c, mapped) => {
      const n = numFromRawOrMapped(raw, mapped, rawKeys, mappedKeys);
      return n == null ? '—' : formatDisplay(n);
    },
  };
}

function walkConditionGroups(groups: ConditionGroupDto[] | undefined, acc: Set<string>) {
  if (!groups?.length) return;
  for (const g of groups) {
    for (const c of g.conditions || []) {
      if (c.enabled === false) continue;
      if (c.indicatorType) acc.add(c.indicatorType);
    }
    walkConditionGroups(g.childGroups, acc);
  }
}

export function collectIndicatorTypesFromStrategyRule(rule: StrategyRuleDto): Set<string> {
  const s = new Set<string>();
  walkConditionGroups(rule.buyConditionGroups, s);
  walkConditionGroups(rule.sellConditionGroups, s);
  return s;
}

export function collectIndicatorTypesFromAlertsAndGlobal(
  alerts: { enabled?: boolean; conditions?: AlertConditionDto[] }[],
  globalConds: AlertConditionDto[],
): Set<string> {
  const s = new Set<string>();
  for (const c of globalConds) {
    if (c.enabled === false) continue;
    if (c.indicatorType) s.add(c.indicatorType);
  }
  for (const a of alerts) {
    if (a.enabled === false) continue;
    for (const c of a.conditions || []) {
      if (c.enabled === false) continue;
      if (c.indicatorType) s.add(c.indicatorType);
    }
  }
  return s;
}

function mapIndicatorTypeToColumns(t: string): StrategyMetricColumn[] {
  switch (t) {
    case 'RSI':
      return [colFromNumber('rsi', 'RSI', ['rsi_14'], ['rsi'])];
    case 'MACD':
      return [
        colFromNumber('macd', 'MACD', ['macd'], ['macdLine']),
        colFromNumber('macd_sig', 'MACD Sig', ['macd_signal'], ['signalLine', 'macdSignal']),
        colFromNumber('macd_hist', 'Hist', ['macd_histogram'], ['macdHistogram', 'histogram']),
      ];
    case 'STOCHASTIC':
    case 'STOCHASTIC_K':
      return [colFromNumber('stoch_k', '%K', ['stoch_k'], ['stochasticK'])];
    case 'STOCHASTIC_D':
      return [colFromNumber('stoch_d', '%D', ['stoch_d'], ['stochasticD'])];
    case 'ADX':
      return [colFromNumber('adx', 'ADX', ['adx'], ['adx'])];
    case 'DMI':
      return [
        colFromNumber('plus_di', '+DI', ['plus_di'], ['plusDI']),
        colFromNumber('minus_di', '-DI', ['minus_di'], ['minusDI']),
      ];
    case 'CCI':
      return [colFromNumber('cci', 'CCI', ['cci'], ['cci', 'cci13'])];
    case 'TRIX':
      return [
        colFromNumber('trix', 'TRIX', ['trix'], ['trix']),
        colFromNumber('trix_sig', 'TRIX Sig', ['trix_signal'], ['trixSignal']),
      ];
    case 'DISPARITY':
      return [colFromNumber('disparity_mid', '이격도', ['disparity_mid'], ['disparityMid'])];
    case 'NEW_PSYCHOLOGICAL':
      return [colFromNumber('new_psy', '신심리', ['new_psy'], ['newPsy', 'newPsychological'])];
    case 'INVEST_PSYCHOLOGICAL':
      return [colFromNumber('invest_psy', '투심', ['invest_psy'], ['investPsy', 'investPsychological'])];
    case 'WILLIAMS_R':
      return [colFromNumber('williams_r', 'W%R', ['williams_r'], ['williamsR'])];
    case 'BWI':
      return [colFromNumber('bwi', 'BWI', ['bwi'], ['bwi'])];
    case 'OBV':
      return [
        colFromNumber('obv', 'OBV', ['obv'], ['obv']),
        colFromNumber('obv_sig', 'OBV Sig', ['obv_signal'], ['obvSignal']),
      ];
    case 'VOLUME_OSC':
      return [colFromNumber('vol_osc', 'VolOSC', ['volume_osc'], ['volumeOsc'])];
    case 'VR':
      return [
        colFromNumber('vr', 'VR', ['vr'], ['vr']),
        colFromNumber('vr2', 'VR2', ['vr2'], ['vr2']),
      ];
    case 'VOLUME':
      return [
        {
          id: 'vol_candle',
          label: '거래량(봉)',
          getCompareValue: (_r, c) => flashCompareNumKey(c.volume),
          getDisplayValue: (_r, c) => formatDisplay(c.volume),
        },
      ];
    default:
      return [];
  }
}

const DEFAULT_EXTRA: StrategyMetricColumn[] = [
  colFromNumber('rsi', 'RSI', ['rsi_14'], ['rsi']),
  colFromNumber('macd', 'MACD', ['macd'], ['macdLine']),
];

export function buildStrategyMetricColumns(types: Set<string>): StrategyMetricColumn[] {
  const out: StrategyMetricColumn[] = [];
  const seen = new Set<string>();
  const add = (cols: StrategyMetricColumn[]) => {
    for (const c of cols) {
      if (seen.has(c.id)) continue;
      seen.add(c.id);
      out.push(c);
    }
  };
  const sorted = Array.from(types).sort();
  for (const t of sorted) {
    add(mapIndicatorTypeToColumns(t));
  }
  if (out.length === 0) add(DEFAULT_EXTRA);
  return out;
}

export const BASE_PRICE_COLUMNS: StrategyMetricColumn[] = [
  {
    id: 'c_ts',
    label: '봉시각(UTC초)',
    getCompareValue: (_r, c) => flashCompareTimeKeyMs(c.timestamp),
    getDisplayValue: (_r, c) => {
      const ms = c.timestamp > 1e12 ? c.timestamp : c.timestamp * 1000;
      return Number.isFinite(ms) ? new Date(ms).toISOString().slice(0, 19) : '—';
    },
  },
  {
    id: 'c_o',
    label: '시가',
    getCompareValue: (_r, c) => flashCompareNumKey(c.open),
    getDisplayValue: (_r, c) => formatDisplay(c.open),
  },
  {
    id: 'c_h',
    label: '고가',
    getCompareValue: (_r, c) => flashCompareNumKey(c.high),
    getDisplayValue: (_r, c) => formatDisplay(c.high),
  },
  {
    id: 'c_l',
    label: '저가',
    getCompareValue: (_r, c) => flashCompareNumKey(c.low),
    getDisplayValue: (_r, c) => formatDisplay(c.low),
  },
  {
    id: 'c_c',
    label: '종가',
    getCompareValue: (_r, c) => flashCompareNumKey(c.close),
    getDisplayValue: (_r, c) => formatDisplay(c.close),
  },
  {
    id: 'c_v',
    label: '거래량',
    getCompareValue: (_r, c) => flashCompareNumKey(c.volume),
    getDisplayValue: (_r, c) => formatDisplay(c.volume),
  },
];

export function buildFlatCompareMap(
  columns: StrategyMetricColumn[],
  raw: Record<string, number>,
  candle: CandleUpdate,
): Record<string, string> {
  const mapped = mapWsIndicatorsToChartFormat(raw as Record<string, unknown>);
  const flat: Record<string, string> = {};
  for (const col of columns) {
    flat[col.id] = col.getCompareValue(raw, candle, mapped);
  }
  return flat;
}

export function buildFlatDisplayMap(
  columns: StrategyMetricColumn[],
  raw: Record<string, number>,
  candle: CandleUpdate,
): Record<string, string> {
  const mapped = mapWsIndicatorsToChartFormat(raw as Record<string, unknown>);
  const flat: Record<string, string> = {};
  for (const col of columns) {
    flat[col.id] = col.getDisplayValue(raw, candle, mapped);
  }
  return flat;
}
