/** 복합지표 — 동일 지표 2개(서로 다른 기간) 간 교차·비교 조건 */
import type { ConditionDSL } from './strategyTypes';

export interface CompositePeriodDef {
  rsiPeriod: number;
  cciPeriod: number;
  adxPeriod: number;
  williamsR: number;
  trixPeriod: number;
  vrPeriod: number;
  newPsy: number;
  investPsy: number;
  dispShort: number;
  dispMid: number;
}

export interface CompositeIndicatorItem {
  value: string;
  label: string;
  desc: string;
}

/** 복합지표 팔레트 — 동일 지표 타입 2인스턴스 교차 */
export const COMPOSITE_INDICATOR_ITEMS: CompositeIndicatorItem[] = [
  { value: 'RSI', label: 'RSI', desc: 'RSI 기간 교차' },
  { value: 'CCI', label: 'CCI', desc: 'CCI 기간 교차' },
  { value: 'ADX', label: 'ADX', desc: 'ADX 기간 교차' },
  { value: 'WILLIAMS_R', label: 'Williams %R', desc: 'Williams %R 교차' },
  { value: 'TRIX', label: 'TRIX', desc: 'TRIX 기간 교차' },
  { value: 'VR', label: 'VR', desc: 'VR 기간 교차' },
  { value: 'PSYCHOLOGICAL', label: '심리도', desc: '심리도 기간 교차' },
  { value: 'INVEST_PSYCHOLOGICAL', label: '투자심리도', desc: '투자심리도 교차' },
  { value: 'DISPARITY', label: '이격도', desc: '이격도 기간 교차' },
];

export function getCompositeDefaultPeriods(ind: string, def: CompositePeriodDef): { short: number; long: number } {
  switch (ind) {
    case 'RSI': return { short: def.rsiPeriod, long: Math.max(def.rsiPeriod * 2, 20) };
    case 'CCI': return { short: def.cciPeriod, long: Math.max(def.cciPeriod * 2, 26) };
    case 'ADX': return { short: def.adxPeriod, long: Math.max(def.adxPeriod * 2, 28) };
    case 'WILLIAMS_R': return { short: def.williamsR, long: Math.max(def.williamsR * 2, 28) };
    case 'TRIX': return { short: def.trixPeriod, long: Math.max(def.trixPeriod * 2, 24) };
    case 'VR': return { short: def.vrPeriod, long: Math.max(def.vrPeriod * 2, 20) };
    case 'PSYCHOLOGICAL':
    case 'NEW_PSYCHOLOGICAL': return { short: def.newPsy, long: Math.max(def.newPsy * 2, 24) };
    case 'INVEST_PSYCHOLOGICAL': return { short: def.investPsy, long: Math.max(def.investPsy * 2, 20) };
    case 'DISPARITY': return { short: def.dispShort, long: def.dispMid };
    default: return { short: 9, long: 20 };
  }
}

export function compositeValueField(ind: string, period: number): string {
  switch (ind) {
    case 'RSI': return `RSI_VALUE_${period}`;
    case 'CCI': return `CCI_VALUE_${period}`;
    case 'ADX': return `ADX_VALUE_${period}`;
    case 'WILLIAMS_R': return `WILLIAMS_R_VALUE_${period}`;
    case 'TRIX': return `TRIX_VALUE_${period}`;
    case 'VR': return `VR_VALUE_${period}`;
    case 'PSYCHOLOGICAL':
    case 'NEW_PSYCHOLOGICAL': return `PSY_VALUE_${period}`;
    case 'INVEST_PSYCHOLOGICAL': return `INVEST_PSY_VALUE_${period}`;
    case 'DISPARITY': return `DISPARITY${period}`;
    default: return `${ind}_VALUE_${period}`;
  }
}

export function parsePeriodFromCompositeField(ind: string, field?: string): number | null {
  if (!field) return null;
  if (ind === 'DISPARITY' && field.startsWith('DISPARITY')) {
    const n = parseInt(field.slice('DISPARITY'.length), 10);
    return Number.isFinite(n) && n > 0 ? n : null;
  }
  const suffix = field.match(/_(\d+)$/);
  if (!suffix) return null;
  const n = parseInt(suffix[1], 10);
  return Number.isFinite(n) && n > 0 ? n : null;
}

export function syncCompositeFields(cond: ConditionDSL): ConditionDSL {
  if (!cond.composite) return cond;
  const leftP = cond.leftPeriod
    ?? parsePeriodFromCompositeField(cond.indicatorType, cond.leftField)
    ?? undefined;
  const rightP = cond.rightPeriod
    ?? parsePeriodFromCompositeField(cond.indicatorType, cond.rightField)
    ?? undefined;
  if (leftP == null || rightP == null) {
    return {
      ...cond,
      composite: true,
      ...(leftP != null ? { leftPeriod: leftP } : null),
      ...(rightP != null ? { rightPeriod: rightP } : null),
    };
  }
  return {
    ...cond,
    composite: true,
    leftPeriod: leftP,
    rightPeriod: rightP,
    leftField: compositeValueField(cond.indicatorType, leftP),
    rightField: compositeValueField(cond.indicatorType, rightP),
    period: undefined,
  };
}

export function normalizeCompositeCondition(cond: ConditionDSL): ConditionDSL {
  if (cond.composite) return syncCompositeFields(cond);
  const leftP = parsePeriodFromCompositeField(cond.indicatorType, cond.leftField);
  const rightP = parsePeriodFromCompositeField(cond.indicatorType, cond.rightField);
  if (leftP && rightP && leftP !== rightP) {
    return syncCompositeFields({
      ...cond,
      composite: true,
      leftPeriod: leftP,
      rightPeriod: rightP,
    });
  }
  return cond;
}

export function makeCompositeCondition(
  ind: string,
  signalType: 'buy' | 'sell',
  def: CompositePeriodDef,
): ConditionDSL {
  const { short, long } = getCompositeDefaultPeriods(ind, def);
  return syncCompositeFields({
    indicatorType: ind,
    conditionType: signalType === 'buy' ? 'CROSS_UP' : 'CROSS_DOWN',
    composite: true,
    leftPeriod: short,
    rightPeriod: long,
    candleRange: 1,
  });
}

export function compositePeriodLabel(ind: string, def: CompositePeriodDef): string {
  const { short, long } = getCompositeDefaultPeriods(ind, def);
  return `${short} / ${long}`;
}

export function compositeDisplayName(ind: string): string {
  const item = COMPOSITE_INDICATOR_ITEMS.find(i => i.value === ind);
  if (item) return `${item.label} + ${item.label}`;
  return `${ind} + ${ind}`;
}

export function compositeElementLabel(ind: string, slot: 1 | 2): string {
  const item = COMPOSITE_INDICATOR_ITEMS.find(i => i.value === ind);
  const name = item?.label ?? ind;
  return `${name} ${slot}`;
}
