/**
 * 단순이동평균(SMA) — MA1~MA11 다중선 설정 및 계산
 */
import type { OHLCVBar } from '../types';
import type { IndicatorConfig } from '../types';
import type { PlotDef } from './indicatorRegistry';
import type { IndicatorResult } from './indicatorRegistry';

export const SMA_MA_COUNT = 11;

/** 소스 기본값 — 종가 */
export const SMA_DEFAULT_SRC = 'close' as const;

export const SMA_SRC_OPTIONS = [
  'close', 'open', 'high', 'low', 'hl2', 'hlc3', 'ohlc4',
] as const;

export type SmaSource = (typeof SMA_SRC_OPTIONS)[number];

/** MA1~MA11 기본 기간 */
export const SMA_DEFAULT_PERIODS = [5, 12, 16, 20, 26, 34, 50, 60, 72, 90, 120] as const;

/** MA1~MA11 기본 색상 */
export const SMA_DEFAULT_COLORS = [
  '#2962FF', '#FF6D00', '#4CAF50', '#E91E63',
  '#9C27B0', '#00BCD4', '#FFC107', '#795548',
  '#607D8B', '#3F51B5', '#8BC34A',
] as const;

/** MA1~MA5 기본 ON, MA6~11 OFF */
export const SMA_DEFAULT_ENABLED = [
  true, true, true, true, true, false, false, false, false, false, false,
] as const;

export function smaPlotId(index: number): string {
  return `plot${index}`;
}

export function smaPeriodKey(maIndex: number): string {
  return `period${maIndex}`;
}

export function createDefaultSmaPlots(): PlotDef[] {
  return SMA_DEFAULT_PERIODS.map((_, i) => ({
    id:        smaPlotId(i),
    title:     `MA${i + 1}`,
    color:     SMA_DEFAULT_COLORS[i],
    type:      'line',
    lineWidth: 2,
    lineStyle: 'solid',
  }));
}

/** 저장·레거시 파라미터에서 유효한 SMA 소스 키 반환 (기본: 종가) */
export function resolveSmaSource(
  params: Record<string, number | string | boolean> | undefined,
): SmaSource {
  const raw = params?.src ?? params?.source;
  const s = typeof raw === 'string' ? raw.trim().toLowerCase() : '';
  if ((SMA_SRC_OPTIONS as readonly string[]).includes(s)) {
    return s as SmaSource;
  }
  return SMA_DEFAULT_SRC;
}

export function createDefaultSmaParams(): Record<string, number | string | boolean> {
  const params: Record<string, number | string | boolean> = { src: SMA_DEFAULT_SRC };
  for (let i = 1; i <= SMA_MA_COUNT; i++) {
    params[smaPeriodKey(i)] = SMA_DEFAULT_PERIODS[i - 1];
  }
  return params;
}

export function createDefaultSmaPlotVisibility(): Record<string, boolean> {
  const vis: Record<string, boolean> = {};
  for (let i = 0; i < SMA_MA_COUNT; i++) {
    vis[smaPlotId(i)] = SMA_DEFAULT_ENABLED[i];
  }
  return vis;
}

/**
 * 레거시 단일 len 파라미터·plot0 단일 플롯 → MA1~11 구성으로 정규화
 */
export function normalizeSmaConfig(config: IndicatorConfig): IndicatorConfig {
  if (config.type !== 'SMA') return config;

  const params: Record<string, number | string | boolean> = {
    ...createDefaultSmaParams(),
    ...config.params,
  };

  // 구버전 len → period1
  const legacyLen = params.len;
  if (legacyLen != null && typeof legacyLen === 'number') {
    if (params.period1 == null || params.period1 === SMA_DEFAULT_PERIODS[0]) {
      params.period1 = legacyLen;
    }
  }
  delete params.len;
  delete params.source;
  params.src = resolveSmaSource(params);

  for (let i = 1; i <= SMA_MA_COUNT; i++) {
    const key = smaPeriodKey(i);
    const v = params[key];
    if (typeof v !== 'number' || v < 1) {
      params[key] = SMA_DEFAULT_PERIODS[i - 1];
    }
  }

  const defaultPlots = createDefaultSmaPlots();
  const savedById = new Map((config.plots ?? []).map(p => [p.id, p]));
  const plots: PlotDef[] = defaultPlots.map((def, i) => {
    const saved = savedById.get(def.id) ?? config.plots?.[i];
    return saved
      ? { ...def, ...saved, id: def.id, title: `MA${i + 1}`, type: 'line' as const }
      : def;
  });

  const plotVisibility: Record<string, boolean> = {
    ...createDefaultSmaPlotVisibility(),
    ...config.plotVisibility,
  };
  for (let i = 0; i < SMA_MA_COUNT; i++) {
    const id = smaPlotId(i);
    if (plotVisibility[id] === undefined) {
      plotVisibility[id] = SMA_DEFAULT_ENABLED[i];
    }
  }

  return { ...config, params, plots, plotVisibility };
}

function sourceValues(bars: OHLCVBar[], src: string): number[] {
  switch (src) {
    case 'open':  return bars.map(b => b.open);
    case 'high':  return bars.map(b => b.high);
    case 'low':   return bars.map(b => b.low);
    case 'hl2':   return bars.map(b => (b.high + b.low) / 2);
    case 'hlc3':  return bars.map(b => (b.high + b.low + b.close) / 3);
    case 'ohlc4': return bars.map(b => (b.open + b.high + b.low + b.close) / 4);
    default:      return bars.map(b => b.close);
  }
}

function computeSma(values: number[], period: number): (number | null)[] {
  const p = Math.max(1, Math.floor(period));
  const out: (number | null)[] = [];
  for (let i = 0; i < values.length; i++) {
    if (i < p - 1) {
      out.push(null);
      continue;
    }
    let sum = 0;
    for (let j = i - p + 1; j <= i; j++) sum += values[j];
    out.push(sum / p);
  }
  return out;
}

/** MA1~MA11 각각 plot0~plot10 데이터 계산 */
export function calculateSmaMulti(
  bars: OHLCVBar[],
  params: Record<string, number | string | boolean>
): IndicatorResult {
  const src = resolveSmaSource(params);
  const values = sourceValues(bars, src);
  const plots: IndicatorResult = {};

  for (let i = 0; i < SMA_MA_COUNT; i++) {
    const periodKey = smaPeriodKey(i + 1);
    const period = Number(params[periodKey] ?? SMA_DEFAULT_PERIODS[i]);
    const sma = computeSma(values, period);
    const plotId = smaPlotId(i);
    plots[plotId] = [];
    for (let j = 0; j < bars.length; j++) {
      const v = sma[j];
      if (v == null || Number.isNaN(v)) continue;
      plots[plotId].push({ time: bars[j].time, value: v });
    }
  }

  return plots;
}
