/** 조건 노드별 지표 기간·임계값 — 차트 DEF 기본값 대비 노드 단위 오버라이드 */
import type { ConditionDSL } from './strategyTypes';
import { getCompositeDefaultPeriods, parsePeriodFromCompositeField, syncCompositeFields, type CompositePeriodDef } from './compositeIndicators';

export interface IndicatorPeriodDef {
  rsiPeriod: number;
  cciPeriod: number;
  adxPeriod: number;
  williamsR: number;
  trixPeriod: number;
  vrPeriod: number;
  newPsy: number;
  investPsy: number;
}

const VALUE_FIELD_PREFIX: Record<string, string> = {
  RSI: 'RSI_VALUE',
  CCI: 'CCI_VALUE',
  ADX: 'ADX_VALUE',
  WILLIAMS_R: 'WILLIAMS_R_VALUE',
  TRIX: 'TRIX_VALUE',
  VR: 'VR_VALUE',
  PSYCHOLOGICAL: 'PSY_VALUE',
  NEW_PSYCHOLOGICAL: 'PSY_VALUE',
  INVEST_PSYCHOLOGICAL: 'INVEST_PSY_VALUE',
};

export function getDefaultIndicatorPeriod(indicatorType: string, def: IndicatorPeriodDef): number {
  switch (indicatorType) {
    case 'RSI': return def.rsiPeriod;
    case 'CCI': return def.cciPeriod;
    case 'ADX': return def.adxPeriod;
    case 'WILLIAMS_R': return def.williamsR;
    case 'TRIX': return def.trixPeriod;
    case 'VR': return def.vrPeriod;
    case 'PSYCHOLOGICAL':
    case 'NEW_PSYCHOLOGICAL': return def.newPsy;
    case 'INVEST_PSYCHOLOGICAL': return def.investPsy;
    default: return 14;
  }
}

function parseFieldPeriod(field?: string): number | null {
  if (!field) return null;
  const m = field.match(/_(\d+)$/);
  if (!m) return null;
  const n = parseInt(m[1], 10);
  return Number.isFinite(n) && n > 0 ? n : null;
}

/** 조건 노드의 RSI 등 값(좌측) 기간 */
export function getConditionValuePeriod(cond: ConditionDSL, def: IndicatorPeriodDef): number {
  if (cond.composite) {
    if (cond.leftPeriod && cond.leftPeriod > 0) return cond.leftPeriod;
    const fromField = parsePeriodFromCompositeField(cond.indicatorType, cond.leftField);
    if (fromField) return fromField;
  }
  if (cond.period && cond.period > 0) return cond.period;
  const fromField = parseFieldPeriod(cond.leftField);
  if (fromField) return fromField;
  return getDefaultIndicatorPeriod(cond.indicatorType, def);
}

export function getConditionRightPeriod(cond: ConditionDSL, def: IndicatorPeriodDef): number {
  if (cond.composite) {
    if (cond.rightPeriod && cond.rightPeriod > 0) return cond.rightPeriod;
    const fromField = parsePeriodFromCompositeField(cond.indicatorType, cond.rightField);
    if (fromField) return fromField;
  }
  const fromField = parseFieldPeriod(cond.rightField);
  if (fromField) return fromField;
  return getDefaultIndicatorPeriod(cond.indicatorType, def);
}

export function usesValuePeriodField(cond: ConditionDSL): boolean {
  if (cond.composite) return true;
  const prefix = VALUE_FIELD_PREFIX[cond.indicatorType];
  if (!prefix) return false;
  const lf = cond.leftField ?? '';
  return lf === prefix || lf.startsWith(`${prefix}_`);
}

export function parseThresholdField(field?: string): number | null {
  if (!field?.startsWith('K_')) return null;
  const n = parseFloat(field.slice(2));
  return Number.isFinite(n) ? n : null;
}

export function thresholdField(value: number): string {
  return `K_${value}`;
}

export function hasEditableThreshold(cond: ConditionDSL): boolean {
  return parseThresholdField(cond.rightField) != null
    || parseThresholdField(cond.leftField) != null;
}

export function getConditionThreshold(cond: ConditionDSL, side: 'left' | 'right'): number | null {
  const field = side === 'left' ? cond.leftField : cond.rightField;
  return parseThresholdField(field);
}

export function setConditionValuePeriod(
  cond: ConditionDSL,
  period: number,
  _def: IndicatorPeriodDef,
): ConditionDSL {
  const p = Math.max(1, Math.min(500, Math.round(period)));
  if (cond.composite) {
    return syncCompositeFields({ ...cond, composite: true, leftPeriod: p });
  }
  const prefix = VALUE_FIELD_PREFIX[cond.indicatorType];
  const next: ConditionDSL = { ...cond, period: p };
  if (prefix && (cond.leftField === prefix || cond.leftField?.startsWith(`${prefix}_`))) {
    next.leftField = `${prefix}_${p}`;
  }
  return next;
}

export function setConditionRightPeriod(cond: ConditionDSL, period: number): ConditionDSL {
  const p = Math.max(1, Math.min(500, Math.round(period)));
  if (!cond.composite) return cond;
  return syncCompositeFields({ ...cond, composite: true, rightPeriod: p });
}

export function setConditionThreshold(
  cond: ConditionDSL,
  side: 'left' | 'right',
  value: number,
): ConditionDSL {
  const fieldKey = side === 'left' ? 'leftField' : 'rightField';
  const current = cond[fieldKey];
  if (!current?.startsWith('K_')) return cond;
  return {
    ...cond,
    [fieldKey]: thresholdField(value),
    targetValue: value,
  };
}

export function initConditionPeriods(
  indicatorType: string,
  condition: ConditionDSL,
  def: IndicatorPeriodDef,
): ConditionDSL {
  if (condition.composite) return condition;
  const prefix = VALUE_FIELD_PREFIX[indicatorType];
  if (!prefix) return condition;
  const period = getDefaultIndicatorPeriod(indicatorType, def);
  const lf = condition.leftField ?? '';
  if (lf === prefix || lf.startsWith(`${prefix}_`)) {
    return { ...condition, period: condition.period ?? period, leftField: `${prefix}_${condition.period ?? period}` };
  }
  return { ...condition, period: condition.period ?? period };
}

export function hasNodeSettings(cond: ConditionDSL): boolean {
  return usesValuePeriodField(cond)
    || hasEditableThreshold(cond)
    || !!cond.composite;
}

const COMMON_PERIODS = [5, 7, 9, 10, 12, 13, 14, 20, 21, 26, 28, 50, 60, 120];

export function getPeriodPresetOptions(indicatorType: string, def: IndicatorPeriodDef): number[] {
  const base = getDefaultIndicatorPeriod(indicatorType, def);
  return [...new Set([base, ...COMMON_PERIODS])].sort((a, b) => a - b);
}

/** 복합지표 요소1(단기)·요소2(장기) 기간 프리셋 */
export function getCompositePeriodPresetOptions(
  indicatorType: string,
  def: IndicatorPeriodDef,
  side: 'left' | 'right',
): number[] {
  const { short, long } = getCompositeDefaultPeriods(indicatorType, def as CompositePeriodDef);
  const base = side === 'left' ? short : long;
  return [...new Set([base, short, long, ...COMMON_PERIODS])].sort((a, b) => a - b);
}

export function getThresholdPresetOptions(indicatorType: string): number[] {
  switch (indicatorType) {
    case 'RSI':
    case 'PSYCHOLOGICAL':
    case 'NEW_PSYCHOLOGICAL':
    case 'INVEST_PSYCHOLOGICAL':
      return [20, 25, 30, 50, 70, 75, 80];
    case 'STOCHASTIC':
      return [20, 50, 80];
    case 'CCI':
      return [-200, -100, -50, 0, 50, 100, 150, 200];
    case 'WILLIAMS_R':
      return [-80, -50, -20];
    case 'ADX':
    case 'DMI':
      return [20, 25, 30, 40, 50];
    case 'VR':
      return [70, 100, 150, 200, 250];
    default:
      return [-100, -50, 0, 50, 100];
  }
}

export function getThresholdBounds(indicatorType: string): { min: number; max: number } {
  switch (indicatorType) {
    case 'RSI':
    case 'PSYCHOLOGICAL':
    case 'NEW_PSYCHOLOGICAL':
    case 'INVEST_PSYCHOLOGICAL':
    case 'STOCHASTIC':
      return { min: 0, max: 100 };
    case 'WILLIAMS_R':
      return { min: -100, max: 0 };
    case 'CCI':
      return { min: -500, max: 500 };
    default:
      return { min: -1000, max: 1000 };
  }
}
