/**
 * 볼린저밴드 (업비트 BB 설정)
 * - 길이(length) 기본 20, 곱(mult) 기본 2, 오프셋(offset) 기본 0
 * - 기준선: 종가 SMA, 표준편차는 모집단(N) 기준
 */
import type { OHLCVBar, Timeframe } from '../types';
import type { PlotData } from './indicatorRegistry';
import { fetchUpbitCandles, isUpbitMarket } from './upbitApi';

export const BB_DEFAULT_LENGTH = 20;
export const BB_DEFAULT_MULT = 2;
export const BB_DEFAULT_OFFSET = 0;

/** 업비트 BB 백그라운드 그리기 기본 (반투명 파랑) */
export const DEFAULT_BB_BAND_BACKGROUND = {
  visible: true,
  color: '#42A5F528',
} as const;

const BB_PLOT_TITLES = ['중앙값', '어퍼', '로우어'] as const;
const BB_PLOT_IDS = ['plot0', 'plot1', 'plot2'] as const;
const BB_DEFAULT_COLORS = ['#FF9800', '#42A5F5', '#42A5F5'] as const;

export type BbSymbolMode = 'main' | 'other';

export type BbBandBackground = { visible: boolean; color: string };

export function resolveBbBandBackground(
  bg?: Partial<BbBandBackground> | null,
): BbBandBackground {
  return {
    visible: bg?.visible !== false,
    color: bg?.color ?? DEFAULT_BB_BAND_BACKGROUND.color,
  };
}

/** 업비트 플롯 정의 병합 (중앙값·어퍼·로우어, 기본 색) */
export function mergeBbPlots(
  saved: import('./indicatorRegistry').PlotDef[] | undefined,
  defaults: import('./indicatorRegistry').PlotDef[],
): import('./indicatorRegistry').PlotDef[] {
  const byId = new Map((saved ?? []).map(p => [p.id, p]));
  return BB_PLOT_IDS.map((id, i) => {
    const def = defaults.find(p => p.id === id) ?? defaults[i];
    const prev = byId.get(id);
    return {
      ...def,
      ...prev,
      id,
      title: BB_PLOT_TITLES[i],
      color: prev?.color ?? BB_DEFAULT_COLORS[i],
    };
  });
}

/** 차트 레전드: BB 20 2 0 SMA */
export function formatBbLegendLabel(
  params: Record<string, number | string | boolean>,
): string {
  const p = normalizeBollingerParams(params);
  const ma = String(p.maType ?? 'SMA').replace(/\s*\(.*\)\s*/g, '').trim();
  return `BB ${p.length} ${p.mult} ${p.offset} ${ma}`;
}

export function normalizeBollingerParams(
  params: Record<string, number | string | boolean>,
): Record<string, number | string | boolean> {
  const length = Math.max(1, Math.round(Number(params.length ?? BB_DEFAULT_LENGTH) || BB_DEFAULT_LENGTH));
  const mult = Math.max(0.001, Number(params.mult ?? BB_DEFAULT_MULT) || BB_DEFAULT_MULT);
  const offset = Math.round(Number(params.offset ?? BB_DEFAULT_OFFSET) || 0);
  const rawMode = String(params.symbolMode ?? 'main');
  const symbolMode: BbSymbolMode = rawMode === 'other' ? 'other' : 'main';
  const refSymbol = String(params.refSymbol ?? '').trim().toUpperCase();
  return {
    ...params,
    length,
    mult,
    offset,
    symbolMode,
    refSymbol,
    src: 'close',
    maType: 'SMA',
  };
}

/** TradingView/업비트 오프셋: 양수면 플롯을 오른쪽(미래)으로 이동 */
export function applyPlotOffset(data: PlotData, offset: number): PlotData {
  if (!offset) return data;
  const n = data.length;
  return data.map((point, i) => {
    const srcIdx = i - offset;
    if (srcIdx < 0 || srcIdx >= n) {
      return { time: point.time, value: NaN };
    }
    return { time: point.time, value: data[srcIdx].value };
  });
}

/** 다른 심볼 캔들을 메인 차트 시간축에 맞춤 (같은 time 키) */
export function alignBarsToMainTimeline(mainBars: OHLCVBar[], refBars: OHLCVBar[]): OHLCVBar[] {
  const byTime = new Map(refBars.map(b => [b.time, b]));
  return mainBars.map(mb => {
    const ref = byTime.get(mb.time);
    if (!ref) {
      return { ...mb, open: NaN, high: NaN, low: NaN, close: NaN, volume: 0 };
    }
    return ref;
  });
}

export async function resolveBollingerBars(
  mainBars: OHLCVBar[],
  params: Record<string, number | string | boolean>,
  timeframe: Timeframe,
): Promise<OHLCVBar[]> {
  const p = normalizeBollingerParams(params);
  if (p.symbolMode !== 'other') return mainBars;
  const ref = String(p.refSymbol ?? '');
  if (!ref || !isUpbitMarket(ref)) return mainBars;
  try {
    const refBars = await fetchUpbitCandles(ref, timeframe, mainBars.length);
    return alignBarsToMainTimeline(mainBars, refBars);
  } catch (e) {
    console.warn('[BB] ref symbol fetch failed:', ref, e);
    return mainBars;
  }
}
