/**
 * 전략 평가 — 저장 전략 × 종목 × 봉 시점 조건 일치율 분석
 */
import '../styles/strategyEvaluation.css';
import '../styles/backtestDashboard.css';
import '../styles/virtualTradingDashboard.css';
import '../styles/strategyEditorTheme.css';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import type { Theme, Timeframe } from '../types';
import {
  loadStrategies,
  loadStrategy,
  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 type { VirtualIndicatorSnapshot } from '../hooks/useVirtualIndicatorSnapshots';
import VirtualTargetSignalPanel from './virtual/VirtualTargetSignalPanel';
import StrategyEvaluationChart from './strategyEvaluation/StrategyEvaluationChart';
import StrategyEvaluationSettingsTab from './strategyEvaluation/StrategyEvaluationSettingsTab';
import { readStoredSize, storeSize, usePanelResize } from './strategyEditor/usePanelResize';
import { getKoreanName } from '../utils/marketNameCache';
import { useIndicatorSettings } from '../hooks/useIndicatorSettings';
import {
  mergeEvalGetParams,
  type EvalIndicatorParams,
} from '../utils/strategyEvaluationParams';
import {
  BACKTEST_STRATEGY_TIMEFRAME,
  buildQuickRunTimeframeSelectOptions,
  resolveBacktestExecTimeframe,
  type BacktestRunTimeframeChoice,
} from '../utils/backtestRunTimeframe';
import type { OHLCVBar } from '../types';

const LEFT_KEY = 'seval-left-width';
const RIGHT_KEY = 'seval-right-width';
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 getEvalParams = useMemo(
    () => mergeEvalGetParams(baseGetParams, appliedIndicatorParams),
    [baseGetParams, appliedIndicatorParams],
  );

  const [leftWidth, setLeftWidth] = useState(() => readMinWidth(LEFT_KEY, LEFT_DEFAULT));
  const [rightWidth, setRightWidth] = useState(() => readMinWidth(RIGHT_KEY, RIGHT_DEFAULT));
  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 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(() => {
    void loadStrategies().then(list => setStrategies(list ?? []));
  }, []);

  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 refreshEvaluation = useCallback(async () => {
    if (!selectedStrategyId || !selectedStrategy || selectedBarTimeSec == null) {
      setSnapshot(undefined);
      return;
    }
    setEvalLoading(true);
    setEvalError(null);
    try {
      const snap = await fetchEvaluationSnapshotAtBar(
        market,
        selectedStrategyId,
        selectedStrategy,
        selectedBarTimeSec,
        appliedIndicatorParams,
      );
      setSnapshot(snap ?? undefined);
    } catch (e) {
      setEvalError(e instanceof Error ? e.message : '조건 평가 실패');
      setSnapshot(undefined);
    } finally {
      setEvalLoading(false);
    }
  }, [market, selectedStrategyId, selectedStrategy, selectedBarTimeSec, appliedIndicatorParams]);

  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">
        <aside className="btd-sidebar" style={{ width: leftWidth, flex: `0 0 ${leftWidth}px` }}>
          <div className="btd-exec-list seval-left-panel">
            <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' ? (
              <>
                <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}
              />
            )}
          </div>
        </aside>

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

        <main className="btd-main">
          <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}
              theme={theme}
              strategy={selectedStrategy}
              selectedBarIndex={selectedBarIndex}
              onSelectedBarIndexChange={setSelectedBarIndex}
              onBarsLoaded={setBars}
              paramsRevision={paramsRevision}
              getParamsOverride={getEvalParams}
              getVisualConfigOverride={getVisualConfig}
            />
          </div>
        </main>

        <div
          className="btd-splitter btd-splitter--v"
          role="separator"
          aria-orientation="vertical"
          aria-label="우측 패널 너비"
          onPointerDown={onRightSplit}
        />

        <aside className="btd-right seval-right-panel" style={{ width: rightWidth, flex: `0 0 ${rightWidth}px` }}>
          <div className="seval-signal-head">
            <span className="seval-signal-market">{getKoreanName(market)}</span>
            <span className="seval-live-dot" title="선택 봉 기준 평가" />
            <span className="seval-live-label">봉 평가</span>
          </div>

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

          <VirtualTargetSignalPanel
            snapshot={snapshot}
            viewMode="summary"
            loading={evalLoading}
            hasStrategy={selectedStrategyId != null}
            className="seval-signal-panel"
          />

          <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>
  );
}
