/**
 * 전략 평가 — 저장 전략 × 종목 × 봉 시점 조건 일치율 분석
 */
import '../styles/backtestDashboard.css';
import '../styles/virtualTradingDashboard.css';
import '../styles/strategyEditorTheme.css';
import '../styles/strategyEvaluation.css';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import type { Theme, Timeframe } from '../types';
import type { VirtualIndicatorSnapshot } from '../hooks/useVirtualIndicatorSnapshots';
import {
  loadStrategies,
  loadStrategy,
  type BacktestSignal,
  type StrategyDto,
} from '../utils/backendApi';
import { hydrateStrategyDto } from '../utils/strategyHydrate';
import { repairUtf8Mojibake } from '../utils/textEncoding';
import { resolveStrategyPrimaryTimeframe } from '../utils/strategyToChartIndicators';
import { fetchEvaluationSnapshotAtBar } from '../utils/strategyEvaluationSnapshot';
import StrategyEvaluationSignalPanel from './strategyEvaluation/StrategyEvaluationSignalPanel';
import StrategyEvaluationChart from './strategyEvaluation/StrategyEvaluationChart';
import StrategyEvaluationSettingsTab from './strategyEvaluation/StrategyEvaluationSettingsTab';
import StrategyEditorModal from './strategyEvaluation/StrategyEditorModal';
import SePanelCollapseHandle from './strategyEditor/SePanelCollapseHandle';
import { readStoredSize, readStoredBool, storeBool, storeSize, usePanelResize } from './strategyEditor/usePanelResize';
import { getKoreanName } from '../utils/marketNameCache';
import { useIndicatorSettings } from '../hooks/useIndicatorSettings';
import {
  mergeEvalGetParams,
  buildEvalParamsFromStrategy,
  type EvalIndicatorParams,
} from '../utils/strategyEvaluationParams';
import {
  BACKTEST_STRATEGY_TIMEFRAME,
  buildQuickRunTimeframeSelectOptions,
  resolveBacktestExecTimeframe,
  type BacktestRunTimeframeChoice,
} from '../utils/backtestRunTimeframe';
import { resolveBarSignalHighlight } from '../utils/strategyEvaluationBarSignals';
import type { OHLCVBar } from '../types';

const LEFT_KEY = 'seval-left-width';
const LEFT_OPEN_KEY = 'seval-left-open';
const RIGHT_KEY = 'seval-right-width';
const RIGHT_OPEN_KEY = 'seval-right-open';
const LEFT_DEFAULT = 380;
const RIGHT_DEFAULT = 440;

type LeftTab = 'strategy' | 'settings';

function readMinWidth(key: string, fallback: number): number {
  return Math.max(readStoredSize(key, fallback), fallback);
}

interface Props {
  theme?: Theme;
}

export default function StrategyEvaluationPage({ theme = 'dark' }: Props) {
  const { getParams: baseGetParams, getVisualConfig } = useIndicatorSettings();
  const [leftTab, setLeftTab] = useState<LeftTab>('strategy');
  const [strategies, setStrategies] = useState<StrategyDto[]>([]);
  const [strategySearch, setStrategySearch] = useState('');
  const [selectedStrategyId, setSelectedStrategyId] = useState<number | null>(null);
  const [selectedStrategy, setSelectedStrategy] = useState<StrategyDto | null>(null);

  const [market, setMarket] = useState('KRW-BTC');
  const [timeframeChoice, setTimeframeChoice] = useState<BacktestRunTimeframeChoice>(BACKTEST_STRATEGY_TIMEFRAME);

  const [bars, setBars] = useState<OHLCVBar[]>([]);
  const [selectedBarIndex, setSelectedBarIndex] = useState(0);
  const [snapshot, setSnapshot] = useState<VirtualIndicatorSnapshot | undefined>();
  const [evalLoading, setEvalLoading] = useState(false);
  const [evalError, setEvalError] = useState<string | null>(null);
  const [appliedIndicatorParams, setAppliedIndicatorParams] = useState<EvalIndicatorParams | null>(null);
  const [paramsRevision, setParamsRevision] = useState(0);
  const [chartLoading, setChartLoading] = useState(false);
  const [backtestSignals, setBacktestSignals] = useState<BacktestSignal[]>([]);
  const [editorModalOpen, setEditorModalOpen] = useState(false);
  const evalSessionRef = useRef(0);
  const paramsRevisionRef = useRef(paramsRevision);

  const getEvalParams = useMemo(
    () => mergeEvalGetParams(baseGetParams, appliedIndicatorParams),
    [baseGetParams, appliedIndicatorParams],
  );

  const [leftWidth, setLeftWidth] = useState(() => readMinWidth(LEFT_KEY, LEFT_DEFAULT));
  const [leftOpen, setLeftOpen] = useState(() => readStoredBool(LEFT_OPEN_KEY, true));
  const [rightWidth, setRightWidth] = useState(() => readMinWidth(RIGHT_KEY, RIGHT_DEFAULT));
  const [rightOpen, setRightOpen] = useState(() => readStoredBool(RIGHT_OPEN_KEY, true));
  const leftRef = useRef(leftWidth);
  const rightRef = useRef(rightWidth);
  leftRef.current = leftWidth;
  rightRef.current = rightWidth;

  const onLeftSplit = usePanelResize('vertical', setLeftWidth, () => leftRef.current, 300, 520, v => storeSize(LEFT_KEY, v));

  const toggleLeftPanel = useCallback(() => {
    setLeftOpen(prev => {
      const next = !prev;
      storeBool(LEFT_OPEN_KEY, next);
      return next;
    });
  }, []);

  const toggleRightPanel = useCallback(() => {
    setRightOpen(prev => {
      const next = !prev;
      storeBool(RIGHT_OPEN_KEY, next);
      return next;
    });
  }, []);

  const leftWrapStyle = useMemo(
    () => ({ '--seval-left-width': `${leftWidth}px` }) as React.CSSProperties,
    [leftWidth],
  );
  const rightWrapStyle = useMemo(
    () => ({ '--seval-right-width': `${rightWidth}px` }) as React.CSSProperties,
    [rightWidth],
  );
  const onRightSplit = useCallback((e: React.PointerEvent<HTMLDivElement>) => {
    const startX = e.clientX;
    const start = rightRef.current;
    document.body.style.cursor = 'col-resize';
    document.body.style.userSelect = 'none';
    e.currentTarget.setPointerCapture(e.pointerId);
    e.currentTarget.classList.add('btd-splitter--active');
    const splitter = e.currentTarget;
    const onMove = (ev: PointerEvent) => {
      const delta = ev.clientX - startX;
      setRightWidth(Math.min(600, Math.max(360, start - delta)));
    };
    const onUp = (ev: PointerEvent) => {
      document.body.style.cursor = '';
      document.body.style.userSelect = '';
      splitter.releasePointerCapture(ev.pointerId);
      splitter.classList.remove('btd-splitter--active');
      window.removeEventListener('pointermove', onMove);
      window.removeEventListener('pointerup', onUp);
      storeSize(RIGHT_KEY, rightRef.current);
    };
    window.addEventListener('pointermove', onMove);
    window.addEventListener('pointerup', onUp);
  }, []);

  const strategyPrimaryTimeframe = useMemo(
    () => (selectedStrategy ? resolveStrategyPrimaryTimeframe(selectedStrategy) : undefined),
    [selectedStrategy],
  );

  const chartTimeframe = useMemo((): Timeframe => {
    return resolveBacktestExecTimeframe(timeframeChoice, strategyPrimaryTimeframe ?? '3m');
  }, [timeframeChoice, strategyPrimaryTimeframe]);

  const tfOptions = useMemo(
    () => buildQuickRunTimeframeSelectOptions(strategyPrimaryTimeframe),
    [strategyPrimaryTimeframe],
  );

  /** 종목·시간봉·전략 변경 — 차트·평가 컨텍스트 초기화 */
  useEffect(() => {
    evalSessionRef.current += 1;
    setSnapshot(undefined);
    setEvalError(null);
    setEvalLoading(true);
    setBars([]);
    setSelectedBarIndex(0);
  }, [market, chartTimeframe, selectedStrategyId]);

  /** 전략설정 파라미터 저장·초기화 */
  useEffect(() => {
    if (paramsRevisionRef.current === paramsRevision) return;
    paramsRevisionRef.current = paramsRevision;
    if (paramsRevision === 0) return;
    evalSessionRef.current += 1;
    setSnapshot(undefined);
    setEvalError(null);
    setEvalLoading(true);
  }, [paramsRevision]);

  useEffect(() => {
    void loadStrategies().then(list => setStrategies(list ?? []));
  }, []);

  const refreshStrategies = useCallback(async () => {
    const list = await loadStrategies();
    const next = list ?? [];
    setStrategies(next);
    if (selectedStrategyId == null) return;
    const still = next.find(s => s.id === selectedStrategyId);
    if (still) {
      setSelectedStrategy(hydrateStrategyDto(still));
      return;
    }
    setSelectedStrategyId(null);
    setSelectedStrategy(null);
    setAppliedIndicatorParams(null);
    setParamsRevision(v => v + 1);
  }, [selectedStrategyId]);

  const handleCloseStrategyEditor = useCallback(() => {
    setEditorModalOpen(false);
    void refreshStrategies();
  }, [refreshStrategies]);

  useEffect(() => {
    if (!selectedStrategyId) {
      setSelectedStrategy(null);
      return;
    }
    let cancelled = false;
    void loadStrategy(selectedStrategyId).then(s => {
      if (cancelled) return;
      setSelectedStrategy(s ? hydrateStrategyDto(s) : null);
    });
    return () => { cancelled = true; };
  }, [selectedStrategyId]);

  const filteredStrategies = useMemo(() => {
    const q = strategySearch.trim().toLowerCase();
    if (!q) return strategies;
    return strategies.filter(s =>
      (s.name ?? '').toLowerCase().includes(q)
      || String(s.id ?? '').includes(q),
    );
  }, [strategies, strategySearch]);

  const selectedBarTimeSec = bars[selectedBarIndex]?.time ?? null;

  const barSignalHighlight = useMemo(
    () => resolveBarSignalHighlight(backtestSignals, selectedBarTimeSec, selectedBarIndex),
    [backtestSignals, selectedBarTimeSec, selectedBarIndex],
  );

  const handleSignalsChange = useCallback((signals: BacktestSignal[]) => {
    setBacktestSignals(signals);
  }, []);

  const refreshEvaluation = useCallback(async () => {
    if (!selectedStrategyId || !selectedStrategy) {
      setSnapshot(undefined);
      setEvalLoading(false);
      return;
    }
    if (chartLoading || bars.length === 0 || selectedBarTimeSec == null) {
      setSnapshot(undefined);
      return;
    }

    const session = evalSessionRef.current;
    setEvalLoading(true);
    setEvalError(null);
    try {
      const indicatorParams = buildEvalParamsFromStrategy(selectedStrategy, getEvalParams);
      const snap = await fetchEvaluationSnapshotAtBar(
        market,
        selectedStrategyId,
        selectedStrategy,
        selectedBarTimeSec,
        indicatorParams,
        bars,
        chartTimeframe,
      );
      if (session !== evalSessionRef.current) return;
      setSnapshot(snap ?? undefined);
    } catch (e) {
      if (session !== evalSessionRef.current) return;
      setEvalError(e instanceof Error ? e.message : '조건 평가 실패');
      setSnapshot(undefined);
    } finally {
      if (session === evalSessionRef.current) {
        setEvalLoading(false);
      }
    }
  }, [
    chartLoading,
    market,
    selectedStrategyId,
    selectedStrategy,
    selectedBarTimeSec,
    selectedBarIndex,
    bars,
    chartTimeframe,
    getEvalParams,
  ]);

  useEffect(() => {
    void refreshEvaluation();
  }, [refreshEvaluation]);

  const handleSelectStrategy = useCallback((s: StrategyDto) => {
    if (s.id == null) return;
    setSelectedStrategyId(s.id);
    setSelectedStrategy(hydrateStrategyDto(s));
    setAppliedIndicatorParams(null);
    setParamsRevision(v => v + 1);
    setTimeframeChoice(BACKTEST_STRATEGY_TIMEFRAME);
    setLeftTab('strategy');
  }, []);

  const handleSelectStrategyById = useCallback((id: number) => {
    const found = strategies.find(s => s.id === id);
    if (found) {
      handleSelectStrategy(found);
      return;
    }
    setSelectedStrategyId(id);
    setSelectedStrategy(null);
    setAppliedIndicatorParams(null);
    setParamsRevision(v => v + 1);
    setTimeframeChoice(BACKTEST_STRATEGY_TIMEFRAME);
    setLeftTab('strategy');
  }, [strategies, handleSelectStrategy]);

  const handleSaveIndicatorParams = useCallback((params: EvalIndicatorParams) => {
    setAppliedIndicatorParams(params);
    setParamsRevision(v => v + 1);
  }, []);

  const handleResetIndicatorParams = useCallback(() => {
    setAppliedIndicatorParams(null);
    setParamsRevision(v => v + 1);
  }, []);

  const strategyLabel = selectedStrategy?.name
    ? repairUtf8Mojibake(selectedStrategy.name)
    : '전략 미선택';

  return (
    <div className={`btd-page se-page se-page--${theme}`}>
      <header className="btd-header">
        <div className="btd-header-brand">
          <h1 className="btd-header-title">전략 평가</h1>
          <span className="btd-header-sub">Strategy Match Analysis</span>
        </div>
      </header>

      <div className="btd-body">
        <div
          className={`seval-left-wrap${leftOpen ? ' seval-left-wrap--open' : ''}`}
          style={leftWrapStyle}
        >
          <aside className={`btd-sidebar seval-left-sidebar${leftOpen ? ' seval-left-sidebar--open' : ''}`}>
            <div className="btd-exec-list seval-left-panel">
            <div className="seval-left-tabs-row">
              <div className="btd-exec-tabs" role="tablist">
                <button
                  type="button"
                  role="tab"
                  aria-selected={leftTab === 'strategy'}
                  className={`btd-exec-tab${leftTab === 'strategy' ? ' btd-exec-tab--on' : ''}`}
                  onClick={() => setLeftTab('strategy')}
                >
                  전략
                </button>
                <button
                  type="button"
                  role="tab"
                  aria-selected={leftTab === 'settings'}
                  className={`btd-exec-tab${leftTab === 'settings' ? ' btd-exec-tab--on' : ''}`}
                  onClick={() => setLeftTab('settings')}
                  disabled={!selectedStrategy}
                >
                  전략설정
                </button>
              </div>
              {leftTab === 'strategy' && (
                <button
                  type="button"
                  className="seval-strategy-add-btn"
                  title="전략 추가·편집"
                  aria-label="전략 추가·편집"
                  onClick={() => setEditorModalOpen(true)}
                >
                  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" aria-hidden>
                    <path d="M12 5v14M5 12h14" strokeLinecap="round" />
                  </svg>
                </button>
              )}
            </div>

            {leftTab === 'strategy' ? (
              <>
                <div className="btd-exec-search">
                  <span className="btd-exec-search-icon" aria-hidden>⌕</span>
                  <input
                    className="btd-exec-search-input"
                    placeholder="전략 검색…"
                    value={strategySearch}
                    onChange={e => setStrategySearch(e.target.value)}
                  />
                  {strategySearch && (
                    <button
                      type="button"
                      className="btd-exec-search-clear"
                      onClick={() => setStrategySearch('')}
                      aria-label="검색어 지우기"
                    >
                      ×
                    </button>
                  )}
                </div>
                <div className="btd-exec-scroll">
                  {filteredStrategies.length === 0 ? (
                    <p className="btd-sidebar-empty">저장된 전략이 없습니다</p>
                  ) : (
                    filteredStrategies.map(s => {
                      const name = repairUtf8Mojibake(s.name ?? `전략 #${s.id}`);
                      const active = selectedStrategyId === s.id;
                      return (
                        <button
                          key={s.id}
                          type="button"
                          className={`btd-exec-item${active ? ' btd-exec-item--active' : ''}`}
                          onClick={() => handleSelectStrategy(s)}
                        >
                          <div className="btd-exec-item-top">
                            <span className="btd-exec-strategy">{name}</span>
                          </div>
                          {s.description && (
                            <p className="btd-exec-meta">{repairUtf8Mojibake(s.description)}</p>
                          )}
                        </button>
                      );
                    })
                  )}
                </div>
              </>
            ) : (
              <StrategyEvaluationSettingsTab
                strategy={selectedStrategy}
                getParams={baseGetParams}
                appliedParams={appliedIndicatorParams}
                onSave={handleSaveIndicatorParams}
                onReset={handleResetIndicatorParams}
                applying={evalLoading || chartLoading}
              />
            )}
          </div>
          </aside>
          <SePanelCollapseHandle
            side="left"
            open={leftOpen}
            onToggle={toggleLeftPanel}
            label="전략 패널"
          />
        </div>

        {leftOpen && (
        <div
          className="btd-splitter btd-splitter--v"
          role="separator"
          aria-orientation="vertical"
          aria-label="좌측 패널 너비"
          onPointerDown={onLeftSplit}
        />
        )}

        <main className={`btd-main${leftOpen ? '' : ' seval-main--left-collapsed'}`}>
          <div className="btd-main-content seval-main-content">
            <StrategyEvaluationChart
              market={market}
              timeframe={chartTimeframe}
              timeframeChoice={timeframeChoice}
              tfOptions={tfOptions}
              strategies={strategies}
              selectedStrategyId={selectedStrategyId}
              onStrategySelect={handleSelectStrategyById}
              onMarketChange={setMarket}
              onTimeframeChoiceChange={setTimeframeChoice}
              onChartLoadingChange={setChartLoading}
              theme={theme}
              strategy={selectedStrategy}
              selectedBarIndex={selectedBarIndex}
              onSelectedBarIndexChange={setSelectedBarIndex}
              onBarsLoaded={setBars}
              paramsRevision={paramsRevision}
              appliedIndicatorParams={appliedIndicatorParams}
              getParamsOverride={getEvalParams}
              getVisualConfigOverride={getVisualConfig}
              evalLoading={evalLoading}
              onSignalsChange={handleSignalsChange}
            />
          </div>
        </main>

        <div
          className={`seval-right-wrap${rightOpen ? ' seval-right-wrap--open' : ''}`}
          style={rightWrapStyle}
        >
          <SePanelCollapseHandle
            side="right"
            open={rightOpen}
            onToggle={toggleRightPanel}
            label="시그널 패널"
          />
          {rightOpen && (
          <div
            className="btd-splitter btd-splitter--v seval-right-splitter"
            role="separator"
            aria-orientation="vertical"
            aria-label="우측 패널 너비"
            onPointerDown={onRightSplit}
          />
          )}
          <aside className={`btd-right seval-right-panel seval-right-sidebar${rightOpen ? ' seval-right-sidebar--open' : ''}`}>
          <div className="seval-signal-head">
            <span className="seval-signal-market">{getKoreanName(market)}</span>
            <span
              className={`seval-live-dot${evalLoading ? ' seval-live-dot--loading' : ''}`}
              title={evalLoading ? '전략 조건 확인 중' : '선택 봉 기준 평가'}
            />
            <span className={`seval-live-label${evalLoading ? ' seval-live-label--loading' : ''}`}>
              {evalLoading ? '조건 확인 중…' : '봉 평가'}
            </span>
          </div>

          {evalError && <p className="seval-eval-error">{evalError}</p>}

          <div className="seval-signal-body">
            <StrategyEvaluationSignalPanel
              snapshot={snapshot}
              strategy={selectedStrategy}
              barTimeSec={selectedBarTimeSec}
              barSignalHighlight={barSignalHighlight}
              hasStrategy={selectedStrategyId != null}
              className="seval-signal-panel"
              getParams={getEvalParams}
            />
          </div>

          <footer className="seval-signal-footer">
            <span className="seval-updated">
              {selectedBarTimeSec != null
                ? new Date(selectedBarTimeSec * 1000).toLocaleString('ko-KR', {
                  month: 'numeric',
                  day: 'numeric',
                  hour: '2-digit',
                  minute: '2-digit',
                })
                : '—'}
              {evalLoading ? ' · 평가 중…' : snapshot?.updatedAt
                ? ` · 갱신 ${new Date(snapshot.updatedAt).toLocaleTimeString('ko-KR')}`
                : ''}
            </span>
            <span className="seval-strategy-chip">{strategyLabel}</span>
          </footer>
          </aside>
        </div>
      </div>

      {editorModalOpen && (
        <StrategyEditorModal
          theme={theme}
          initialStrategyId={selectedStrategyId}
          onClose={handleCloseStrategyEditor}
          onStrategiesChanged={() => { void refreshStrategies(); }}
        />
      )}
    </div>
  );
}
