/**
 * 보조지표 설정 폼 — 개별 설정 모달·일괄 설정 팝업에서 동일 UI/로직 공유
 */
import React, { useState, useCallback, useEffect, useRef } from 'react';
import type { IndicatorConfig, Timeframe } from '../types';
import { getIndicatorDef } from '../utils/indicatorRegistry';
import type { PlotDef, HLineDef } from '../utils/indicatorRegistry';
import { getNumericParamSpec } from '../utils/indicatorParamSpec';
import NumericParamInput from './NumericParamInput';
import SmaPeriodInput from './SmaPeriodInput';
import {
  SMA_DEFAULT_SRC,
  SMA_MA_COUNT,
  smaPeriodKey,
  smaPlotId,
  formatSmaMaDisplayLabel,
} from '../utils/smaConfig';
import PlotLineStylePicker from './PlotLineStylePicker';
import {
  GlobalParamRow,
  IchimokuCloudSection,
  BollingerSymbolSection,
  BollingerBackgroundRow,
  SettingsOutputFooter,
  UnifiedIndicatorBody,
} from './IndicatorSettingsSections';
import {
  createEditorSnapshot,
  configFromEditorSnapshot,
  resetConfigToDefaults,
  type IndicatorSettingsEditorSnapshot,
} from '../utils/indicatorSettingsEditor';

export const ALL_TIMEFRAMES: { tf: Timeframe; label: string }[] = [
  { tf: '1m',  label: '1분'  },
  { tf: '3m',  label: '3분'  },
  { tf: '5m',  label: '5분'  },
  { tf: '10m', label: '10분' },
  { tf: '15m', label: '15분' },
  { tf: '30m', label: '30분' },
  { tf: '1h',  label: '1시간' },
  { tf: '4h',  label: '4시간' },
  { tf: '1D',  label: '일봉'  },
  { tf: '1W',  label: '주봉'  },
  { tf: '1M',  label: '월봉'  },
];

export interface IndicatorSettingsFormProps {
  config: IndicatorConfig;
  chartMarket?: string;
  /** embedded: 일괄 설정 카드 안 */
  variant?: 'modal' | 'embedded';
  /**
   * modal: 편집 중 부모 setState 없이 ref만 갱신 (포커스 유지).
   * embedded: 변경 즉시 onChange 호출.
   */
  deferParentSync?: boolean;
  /** @deprecated 탭 제거 — 통합 화면만 사용 */
  inputsOnly?: boolean;
  /** 개별 설정 모달: 지표 전체 표시 여부 */
  chartHidden?: boolean;
  onChartHiddenChange?: (showOnChart: boolean) => void;
  onChange: (updated: IndicatorConfig) => void;
}

function configFingerprint(c: IndicatorConfig): string {
  return JSON.stringify({
    id: c.id,
    params: c.params,
    plots: c.plots,
    plotVisibility: c.plotVisibility,
    hlines: c.hlines,
    hlinesBackground: c.hlinesBackground,
    bandBackground: c.bandBackground,
    cloudColors: c.cloudColors,
    lastValueVisible: c.lastValueVisible,
    timeframeVisibility: c.timeframeVisibility,
    hidden: c.hidden,
  });
}

const IndicatorSettingsForm: React.FC<IndicatorSettingsFormProps> = ({
  config,
  chartMarket = '',
  variant = 'modal',
  deferParentSync = variant === 'modal',
  inputsOnly = false,
  chartHidden = false,
  onChartHiddenChange,
  onChange,
}) => {
  const def = getIndicatorDef(config.type);
  const isSma = config.type === 'SMA';
  const isIchimoku = config.type === 'IchimokuCloud';
  const isBollinger = config.type === 'BollingerBands';

  const [snap, setSnap] = useState(() => createEditorSnapshot(config));
  const baseRef = useRef(config);
  const fpRef = useRef(configFingerprint(config));
  const onChangeRef = useRef(onChange);
  const internalEmitRef = useRef(false);
  onChangeRef.current = onChange;

  const emitDraft = useCallback((next: IndicatorSettingsEditorSnapshot) => {
    const updated = configFromEditorSnapshot(baseRef.current, next);
    baseRef.current = updated;
    if (deferParentSync) {
      onChangeRef.current(updated);
      return;
    }
    internalEmitRef.current = true;
    onChangeRef.current(updated);
  }, [deferParentSync]);

  const scheduleDraftEmit = useCallback((next: IndicatorSettingsEditorSnapshot) => {
    if (deferParentSync) {
      emitDraft(next);
      return;
    }
    emitDraft(next);
  }, [deferParentSync, emitDraft]);

  useEffect(() => {
    if (deferParentSync) return;
    if (internalEmitRef.current) {
      internalEmitRef.current = false;
      fpRef.current = configFingerprint(config);
      baseRef.current = config;
      return;
    }
    const fp = configFingerprint(config);
    if (fp !== fpRef.current) {
      fpRef.current = fp;
      baseRef.current = config;
      setSnap(createEditorSnapshot(config));
    }
  }, [config, deferParentSync]);

  const emit = useCallback((next: IndicatorSettingsEditorSnapshot) => {
    setSnap(next);
    scheduleDraftEmit(next);
  }, [scheduleDraftEmit]);

  const patch = useCallback((partial: Partial<IndicatorSettingsEditorSnapshot>) => {
    setSnap(prev => {
      const next = { ...prev, ...partial };
      scheduleDraftEmit(next);
      return next;
    });
  }, [scheduleDraftEmit]);

  const { params, plots, plotVis, hlines, hlinesBg, lastValueVisible, timeframeVis, cloudColors, bandBg } = snap;
  const hasHLines = (def?.hlines ?? []).length > 0 || hlines.length > 0;

  const handleHLineVisible = useCallback((idx: number, visible: boolean) =>
    patch({ hlines: hlines.map((h, i) => i === idx ? { ...h, visible } : h) }), [hlines, patch]);
  const handleHLinePrice = useCallback((idx: number, price: number) =>
    patch({ hlines: hlines.map((h, i) => i === idx ? { ...h, price } : h) }), [hlines, patch]);
  const handleHLinePlotStyle = useCallback((idx: number, p: Partial<HLineDef>) =>
    patch({ hlines: hlines.map((h, i) => i === idx ? { ...h, ...p } : h) }), [hlines, patch]);

  const handleParamChange = useCallback((key: string, raw: string | boolean) => {
    const oldVal = params[key];
    const defVal = def?.defaultParams?.[key];
    let nextParams: Record<string, number | string | boolean>;
    if (typeof oldVal === 'number' || typeof defVal === 'number') {
      const n = parseFloat(raw as string);
      const fallback = typeof oldVal === 'number' ? oldVal : (defVal as number);
      nextParams = { ...params, [key]: isNaN(n) ? fallback : n };
    } else if (typeof oldVal === 'boolean' || typeof defVal === 'boolean') {
      nextParams = { ...params, [key]: raw as boolean };
    } else {
      nextParams = { ...params, [key]: raw as string };
    }
    let nextPlotVis = plotVis;
    if (key === 'maType' && (config.type === 'CCI' || config.type === 'RSI')) {
      nextPlotVis = { ...plotVis, plot1: raw !== 'None' };
    }
    patch({ params: nextParams, plotVis: nextPlotVis });
  }, [params, plotVis, def, config.type, patch]);

  const handlePlotStyle = useCallback((idx: number, p: Partial<PlotDef>) => {
    patch({ plots: plots.map((pl, i) => i === idx ? { ...pl, ...p } : pl) });
  }, [plots, patch]);

  const handlePlotToggle = useCallback((plotId: string, enabled: boolean) => {
    patch({ plotVis: { ...plotVis, [plotId]: enabled } });
  }, [plotVis, patch]);

  const handleSmaPeriod = useCallback((maIndex: number, v: number) => {
    const nextParams = { ...params, [smaPeriodKey(maIndex)]: v };
    const nextPlots = plots.map((pl, i) =>
      i === maIndex - 1
        ? { ...pl, title: formatSmaMaDisplayLabel(nextParams, maIndex) }
        : pl,
    );
    patch({ params: nextParams, plots: nextPlots });
  }, [params, plots, patch]);

  const handleSmaToggle = useCallback((plotIndex: number, enabled: boolean) => {
    patch({ plotVis: { ...plotVis, [smaPlotId(plotIndex)]: enabled } });
  }, [plotVis, patch]);

  const handleDefaults = useCallback(() => {
    const reset = resetConfigToDefaults(config);
    baseRef.current = reset;
    fpRef.current = configFingerprint(reset);
    const nextSnap = createEditorSnapshot(reset);
    setSnap(nextSnap);
    onChange(reset);
  }, [config, onChange]);

  const footerProps = {
    lastValueVisible,
    onLastValueVisible: (v: boolean) => patch({ lastValueVisible: v }),
    timeframeVis,
    onTimeframeVis: (tf: Timeframe, v: boolean) =>
      patch({ timeframeVis: { ...timeframeVis, [tf]: v } }),
    timeframes: ALL_TIMEFRAMES,
    chartHidden,
    onChartHidden: onChartHiddenChange,
  };

  const sectionClass = variant === 'embedded'
    ? 'ism-section unified-settings-section ibsm-embedded-form'
    : 'ism-section unified-settings-section';

  return (
    <div className={sectionClass}>
      {variant === 'embedded' && (
        <div className="ibsm-form-toolbar">
          <button type="button" className="ibsm-form-defaults" onClick={handleDefaults}>
            기본값
          </button>
        </div>
      )}

      {isSma && (
        <div className="sma-inputs-section">
          <GlobalParamRow
            indicatorType="SMA"
            paramKey="src"
            value={String(params.src ?? SMA_DEFAULT_SRC)}
            onChange={(_, raw) => patch({ params: { ...params, src: raw as string } })}
          />
          <div className="ism-sma-divider" />
          {Array.from({ length: SMA_MA_COUNT }, (_, i) => {
            const maNum = i + 1;
            const plotId = smaPlotId(i);
            const periodKey = smaPeriodKey(maNum);
            const enabled = plotVis[plotId] !== false;
            const plot = plots[i];
            return (
              <div key={plotId} className={`ism-row ism-sma-ma-row${enabled ? '' : ' ism-sma-ma-off'}`}>
                <label className="ism-toggle ism-sma-ma-toggle">
                  <input
                    type="checkbox"
                    checked={enabled}
                    onChange={e => handleSmaToggle(i, e.target.checked)}
                  />
                  <span className="ism-toggle-slider" />
                </label>
                <label className="ism-label ism-sma-ma-label">
                  {formatSmaMaDisplayLabel(params, maNum)}
                </label>
                <div
                  className="ism-control ism-sma-ma-control"
                  onMouseDown={e => e.stopPropagation()}
                  onPointerDown={e => e.stopPropagation()}
                >
                  <SmaPeriodInput
                    value={Number(params[periodKey] ?? 1)}
                    disabled={!enabled}
                    onCommit={v => handleSmaPeriod(maNum, v)}
                  />
                  {plot && !inputsOnly && (
                    <PlotLineStylePicker
                      disabled={!enabled}
                      title={formatSmaMaDisplayLabel(params, maNum)}
                      value={{
                        color: plot.color,
                        lineWidth: plot.lineWidth,
                        lineStyle: plot.lineStyle,
                      }}
                      onChange={p => handlePlotStyle(i, p)}
                    />
                  )}
                </div>
              </div>
            );
          })}
          {!inputsOnly && <SettingsOutputFooter {...footerProps} />}
        </div>
      )}

      {isIchimoku && (
        <UnifiedIndicatorBody
          config={config}
          params={params}
          plots={plots}
          plotVis={plotVis}
          hlines={[]}
          hlinesBg={hlinesBg}
          hasHLines={false}
          lastValueVisible={lastValueVisible}
          timeframeVis={timeframeVis}
          timeframes={ALL_TIMEFRAMES}
          onParamChange={handleParamChange}
          onPlotToggle={handlePlotToggle}
          onPlotStyle={handlePlotStyle}
          onHLineVisible={handleHLineVisible}
          onHLinePrice={handleHLinePrice}
          onHLineStyle={handleHLinePlotStyle}
          onHlinesBg={v => patch({ hlinesBg: v })}
          onLastValueVisible={v => patch({ lastValueVisible: v })}
          onTimeframeVis={(tf, v) => patch({ timeframeVis: { ...timeframeVis, [tf]: v } })}
          chartHidden={chartHidden}
          onChartHidden={onChartHiddenChange}
          cloudSection={inputsOnly ? undefined : (
            <IchimokuCloudSection
              cloudColors={cloudColors}
              onChange={p => patch({ cloudColors: { ...cloudColors, ...p } })}
            />
          )}
          inputsOnly={inputsOnly}
          showOutputFooter={!inputsOnly}
        />
      )}

      {!isSma && !isIchimoku && (
        <UnifiedIndicatorBody
          config={config}
          params={params}
          plots={plots}
          plotVis={plotVis}
          hlines={hlines}
          hlinesBg={hlinesBg}
          hasHLines={hasHLines}
          lastValueVisible={lastValueVisible}
          timeframeVis={timeframeVis}
          timeframes={ALL_TIMEFRAMES}
          onParamChange={handleParamChange}
          onPlotToggle={handlePlotToggle}
          onPlotStyle={handlePlotStyle}
          onHLineVisible={handleHLineVisible}
          onHLinePrice={handleHLinePrice}
          onHLineStyle={handleHLinePlotStyle}
          onHlinesBg={v => patch({ hlinesBg: v })}
          onLastValueVisible={v => patch({ lastValueVisible: v })}
          onTimeframeVis={(tf, v) => patch({ timeframeVis: { ...timeframeVis, [tf]: v } })}
          chartHidden={chartHidden}
          onChartHidden={onChartHiddenChange}
          inputsOnly={inputsOnly}
          showOutputFooter={!inputsOnly && !isBollinger}
          symbolSection={isBollinger ? (
            <BollingerSymbolSection
              symbolMode={String(params.symbolMode ?? 'main')}
              refSymbol={String(params.refSymbol ?? '')}
              chartMarket={chartMarket}
              onChange={p => {
                const next = { ...params };
                if (p.symbolMode !== undefined) next.symbolMode = p.symbolMode;
                if (p.refSymbol !== undefined) next.refSymbol = p.refSymbol;
                patch({ params: next });
              }}
            />
          ) : undefined}
          afterPlotsSection={isBollinger ? (
            <BollingerBackgroundRow value={bandBg} onChange={v => patch({ bandBg: v })} />
          ) : undefined}
        />
      )}
    </div>
  );
};

export default IndicatorSettingsForm;
