/**
 * BacktestHistoryPage — Golden Analysis Command Center (참조 UI 3열)
 */
import '../styles/backtestDashboard.css';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import ReactDOM from 'react-dom';
import { MarketSearchPanel } from './MarketSearchPanel';
import {
  loadBacktestResults,
  deleteBacktestResult,
  loadPaperTrades,
  loadPaperSummary,
  loadStrategies,
  runBacktest,
  loadBacktestSettings,
  API_BASE,
  type BacktestResultRecord,
  type BacktestAnalysis,
  type BacktestSignal,
  type StrategyDto,
} from '../utils/backendApi';
import { timeframeToCandleType } from '../utils/chartCandleType';
import type { Theme, Timeframe } from '../types';
import { buildEquityFromSignals } from '../utils/backtestEquity';
import {
  formatChartTypeKo,
  formatTimeframeKo,
  normalizeEpochSec,
  normalizeEpochSecOptional,
  toUpbitMarket,
} from '../utils/backtestUiUtils';
import BacktestExecutionList, { type ExecutionListTab } from './backtest/BacktestExecutionList';
import BacktestAnalysisChart from './backtest/BacktestAnalysisChart';
import BacktestKpiPanel from './backtest/BacktestKpiPanel';
import BacktestTradeHistoryCard from './backtest/BacktestTradeHistoryCard';
import BacktestAnalysisReportModal from './backtest/BacktestAnalysisReportModal';
import {
  buildBacktestReportModel,
  buildLiveReportModel,
} from '../utils/backtestReportModel';
import { buildLiveExecutionItems, paperTradesToSignals, type LiveExecutionItem } from '../utils/liveExecutionGroups';
import { PAPER_TRADES_CHANGED_EVENT } from '../utils/paperTradeEvents';
import {
  readStoredSize,
  storeSize,
  usePanelResize,
} from './strategyEditor/usePanelResize';
import '../styles/strategyEditorTheme.css';
import { getKoreanName } from '../utils/marketNameCache';
import { repairUtf8Mojibake } from '../utils/textEncoding';
import { enrichStrategyNameMap, strategyNamesFromList } from '../utils/strategyNameResolver';

const LEFT_KEY = 'btd-left-width';
const RIGHT_KEY = 'btd-right-width';
const BACKTEST_FOCUS_KEY = 'backtest_focus_id';
const LEFT_DEFAULT = 380;
const RIGHT_DEFAULT = 440;

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

function parseDetail(r: BacktestResultRecord) {
  let analysis: BacktestAnalysis | null = null;
  let signals: BacktestSignal[] = [];
  try {
    if (r.analysisJson) analysis = JSON.parse(r.analysisJson);
    if (r.signalsJson) signals = JSON.parse(r.signalsJson);
  } catch { /* ignore */ }
  return { analysis, signals };
}

interface Props {
  theme?: Theme;
}

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

export function BacktestHistoryPage({ theme = 'dark' }: Props) {
  const [tab, setTab] = useState<ExecutionListTab>('backtest');
  const [records, setRecords] = useState<BacktestResultRecord[]>([]);
  const [liveItems, setLiveItems] = useState<LiveExecutionItem[]>([]);
  const [selectedBacktest, setSelectedBacktest] = useState<BacktestResultRecord | null>(null);
  const [selectedLive, setSelectedLive] = useState<LiveExecutionItem | null>(null);
  const [loading, setLoading] = useState(true);
  const [reportOpen, setReportOpen] = useState(false);
  const [strategies, setStrategies] = useState<StrategyDto[]>([]);

  // ── 빠른 백테스팅 실행 ──────────────────────────────────────────────────────
  const [runMarket, setRunMarket] = useState<string>('KRW-BTC');
  const [runTimeframe, setRunTimeframe] = useState<Timeframe>('1D');
  const [runStrategyId, setRunStrategyId] = useState<number | null>(null);
  const [runLoading, setRunLoading] = useState(false);
  const [runError, setRunError] = useState<string | null>(null);
  const [showMarketSearch, setShowMarketSearch] = useState(false);
  const [marketQuery, setMarketQuery] = useState('');
  const marketBtnRef = useRef<HTMLButtonElement>(null);

  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 refreshLiveTrades = useCallback(async () => {
    const [trades, summary, strategies] = await Promise.all([
      loadPaperTrades(),
      loadPaperSummary(),
      loadStrategies(),
    ]);
    const baseNames = strategyNamesFromList(strategies);
    const strategyNames = await enrichStrategyNameMap(
      baseNames,
      trades.map(t => t.strategyId),
    );
    const live = buildLiveExecutionItems(trades, summary, strategyNames);
    setLiveItems(live);
    setSelectedLive(prev => (prev && live.some(x => x.id === prev.id) ? prev : live[0] ?? null));
  }, []);

  const fetchAll = useCallback(async () => {
    setLoading(true);
    const [list, trades, summary, strategies] = await Promise.all([
      loadBacktestResults(),
      loadPaperTrades(),
      loadPaperSummary(),
      loadStrategies(),
    ]);
    const baseNames = strategyNamesFromList(strategies);
    const strategyNames = await enrichStrategyNameMap(
      baseNames,
      [
        ...trades.map(t => t.strategyId),
        ...list.map(r => r.strategyId),
      ],
    );
    const live = buildLiveExecutionItems(trades, summary, strategyNames);
    const enrichedRecords = list.map(r => ({
      ...r,
      strategyName: r.strategyName?.trim()
        || (r.strategyId != null ? strategyNames[r.strategyId] : undefined)
        || r.strategyName
        || '전략 없음',
    }));
    setStrategies(strategies);
    setRecords(enrichedRecords);
    setLiveItems(live);

    // 전략빌더에서 백테스팅 실행 후 자동 선택
    let focusId: number | null = null;
    try {
      const stored = sessionStorage.getItem(BACKTEST_FOCUS_KEY);
      if (stored) { focusId = Number(stored); sessionStorage.removeItem(BACKTEST_FOCUS_KEY); }
    } catch { /* ignore */ }
    const focusRecord = focusId ? list.find(r => r.id === focusId) ?? null : null;

    setSelectedBacktest(prev => focusRecord ?? (prev && list.some(x => x.id === prev.id) ? prev : list[0] ?? null));
    setSelectedLive(prev => (prev && live.some(x => x.id === prev.id) ? prev : live[0] ?? null));
    if (focusRecord) setTab('backtest');
    setLoading(false);
  }, []);

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

  useEffect(() => {
    const onTradesChanged = () => { void refreshLiveTrades(); };
    window.addEventListener(PAPER_TRADES_CHANGED_EVENT, onTradesChanged);
    return () => window.removeEventListener(PAPER_TRADES_CHANGED_EVENT, onTradesChanged);
  }, [refreshLiveTrades]);

  const deleteAll = useCallback(async () => {
    if (records.length === 0) return;
    if (!window.confirm(`전체 ${records.length}개 백테스팅 결과를 삭제하시겠습니까?`)) return;
    await Promise.all(records.map(r => deleteBacktestResult(r.id)));
    await fetchAll();
  }, [records, fetchAll]);

  const handleQuickRun = useCallback(async () => {
    if (!runStrategyId) {
      window.alert('전략을 선택해주세요.');
      return;
    }
    setRunLoading(true);
    setRunError(null);
    try {
      const [settings, barsRes] = await Promise.all([
        loadBacktestSettings(),
        fetch(`${API_BASE}/candles/history?${new URLSearchParams({
          market: runMarket,
          type:   timeframeToCandleType(runTimeframe),
          count:  '800',
        })}`),
      ]);
      if (!barsRes.ok) throw new Error(`캔들 로딩 실패 (${barsRes.status})`);
      const bars = (await barsRes.json()) as Array<{
        time: number; open: number; high: number; low: number; close: number; volume: number;
      }>;
      if (bars.length < 5) {
        throw new Error('캔들 데이터가 부족합니다. 잠시 후 다시 시도하거나 타임프레임을 변경해 주세요.');
      }
      const strategy = strategies.find(s => s.id === runStrategyId);
      const result = await runBacktest({
        strategyId:   runStrategyId,
        bars,
        timeframe:    runTimeframe,
        settings,
        symbol:       runMarket,
        strategyName: strategy?.name,
      });
      if (!result) throw new Error('백테스팅 실행에 실패했습니다.');
      // 결과 목록 갱신 후 새 결과 자동 선택
      await fetchAll();
      setTab('backtest');
    } catch (e) {
      setRunError(e instanceof Error ? e.message : '실행 중 오류가 발생했습니다.');
    } finally {
      setRunLoading(false);
    }
  }, [runMarket, runTimeframe, runStrategyId, strategies, fetchAll]);

  const backtestDetail = selectedBacktest ? parseDetail(selectedBacktest) : null;

  const activeSignals = useMemo((): BacktestSignal[] => {
    if (tab === 'backtest') return backtestDetail?.signals ?? [];
    if (!selectedLive) return [];
    return paperTradesToSignals(selectedLive.trades);
  }, [tab, backtestDetail, selectedLive]);

  const equityData = useMemo(() => {
    if (tab === 'backtest' && backtestDetail?.analysis) {
      return buildEquityFromSignals(
        backtestDetail.signals,
        backtestDetail.analysis.initialCapital,
        selectedBacktest!.symbol,
      );
    }
    if (tab === 'live' && selectedLive) {
      return buildEquityFromSignals(paperTradesToSignals(selectedLive.trades), 10_000_000, selectedLive.symbol);
    }
    return { curve: [], markers: [], trades: [] };
  }, [tab, backtestDetail, selectedBacktest, selectedLive]);

  const chartProps = useMemo(() => {
    if (tab === 'backtest' && selectedBacktest) {
      const signals = backtestDetail?.signals ?? [];
      const signalMax = signals.reduce((m, s) => Math.max(m, s.time ?? 0), 0);
      const toSec = normalizeEpochSec(selectedBacktest.toTime) || signalMax || Math.floor(Date.now() / 1000);
      const fromSec = normalizeEpochSecOptional(selectedBacktest.fromTime);
      return {
        symbol: selectedBacktest.symbol,
        timeframe: selectedBacktest.timeframe,
        toTimeSec: toSec,
        fromTimeSec: fromSec > 0 ? fromSec : undefined,
        barCount: selectedBacktest.barCount || 300,
        strategyId: selectedBacktest.strategyId,
      };
    }
    if (tab === 'live' && selectedLive?.trades.length) {
      const last = selectedLive.trades[selectedLive.trades.length - 1];
      const ts = last.createdAt ? Math.floor(new Date(last.createdAt).getTime() / 1000) : Math.floor(Date.now() / 1000);
      return {
        symbol: selectedLive.symbol,
        timeframe: '1h',
        toTimeSec: ts,
        fromTimeSec: undefined as number | undefined,
        barCount: 300,
        strategyId: selectedLive.trades.find(t => t.strategyId)?.strategyId ?? null,
      };
    }
    return null;
  }, [tab, selectedBacktest, selectedLive, backtestDetail]);

  const centerHead = useMemo(() => {
    if (tab === 'backtest' && selectedBacktest) {
      const market = toUpbitMarket(selectedBacktest.symbol);
      return {
        ko: getKoreanName(market),
        strategy: selectedBacktest.strategyName || '전략 없음',
        metaParts: [
          formatTimeframeKo(selectedBacktest.timeframe),
          formatChartTypeKo('candlestick'),
        ],
      };
    }
    if (tab === 'live' && selectedLive) {
      const market = toUpbitMarket(selectedLive.symbol);
      return {
        ko: getKoreanName(market),
        strategy: selectedLive.strategyLabel,
        metaParts: [
          formatTimeframeKo(chartProps?.timeframe ?? '1h'),
          formatChartTypeKo('candlestick'),
          selectedLive.sourceLabel,
        ],
      };
    }
    return null;
  }, [tab, selectedBacktest, selectedLive, chartProps]);

  const footerTrades = equityData.trades;

  const strategyNamesById = useMemo(
    () => Object.fromEntries(
      strategies.map(s => [s.id, repairUtf8Mojibake(s.name)]),
    ),
    [strategies],
  );

  const reportModel = useMemo(() => {
    if (tab === 'backtest' && selectedBacktest && backtestDetail?.analysis) {
      return buildBacktestReportModel(
        selectedBacktest,
        backtestDetail.analysis,
        backtestDetail.signals,
        strategyNamesById,
      );
    }
    if (tab === 'live' && selectedLive) {
      return buildLiveReportModel(selectedLive, activeSignals);
    }
    return null;
  }, [tab, selectedBacktest, backtestDetail, selectedLive, activeSignals, strategyNamesById]);

  const showRightDetail = tab === 'backtest'
    ? backtestDetail?.analysis != null
    : selectedLive != null;

  if (loading) {
    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">Golden Analysis Command Center</span>
          </div>
        </header>
        <div className="btd-loading">분석 데이터 로딩 중…</div>
      </div>
    );
  }

  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">Golden Analysis Command Center</span>
        </div>

        {/* 빠른 실행 툴바 */}
        <div className="btd-header-run">
          <button
            ref={marketBtnRef}
            type="button"
            className="btd-run-market-btn"
            disabled={runLoading}
            title="종목 검색"
            onClick={() => {
              setMarketQuery('');
              setShowMarketSearch(v => !v);
            }}
          >
            <span className="btd-run-market-ko">{getKoreanName(runMarket)}</span>
            <span className="btd-run-market-sym">{runMarket.replace('KRW-', '')}</span>
            <svg className="btd-run-market-caret" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
              <polyline points="6 9 12 15 18 9"/>
            </svg>
          </button>
          {showMarketSearch && ReactDOM.createPortal(
            <MarketSearchPanel
              currentMarket={runMarket}
              query={marketQuery}
              onQueryChange={setMarketQuery}
              onSelect={market => {
                setRunMarket(market);
                setShowMarketSearch(false);
                setMarketQuery('');
              }}
              onClose={() => {
                setShowMarketSearch(false);
                setMarketQuery('');
              }}
              anchorRect={marketBtnRef.current?.getBoundingClientRect() ?? null}
              anchorPlacement="dropdown"
            />,
            document.body,
          )}
          <select
            className="btd-run-select"
            value={runTimeframe}
            onChange={e => setRunTimeframe(e.target.value as Timeframe)}
            disabled={runLoading}
            title="타임프레임"
          >
            {QUICK_RUN_TIMEFRAMES.map(tf => (
              <option key={tf.value} value={tf.value}>{tf.label}</option>
            ))}
          </select>
          <select
            className="btd-run-select btd-run-select--strategy"
            value={runStrategyId ?? ''}
            onChange={e => setRunStrategyId(e.target.value ? Number(e.target.value) : null)}
            disabled={runLoading}
            title="전략"
          >
            <option value="">전략 선택</option>
            {strategies.map(s => (
              <option key={s.id} value={s.id}>{s.name}</option>
            ))}
          </select>
          <button
            type="button"
            className={`btd-run-btn${runLoading ? ' btd-run-btn--loading' : ''}`}
            disabled={!runStrategyId || runLoading}
            onClick={() => void handleQuickRun()}
            title="백테스팅 실행"
          >
            {runLoading ? (
              <span className="btd-run-spinner" />
            ) : (
              <svg viewBox="0 0 16 16" width="13" height="13" fill="currentColor" aria-hidden="true">
                <path d="M3 2.5l10 5.5-10 5.5V2.5z" />
              </svg>
            )}
          </button>
          {runError && (
            <span className="btd-run-error" title={runError}>⚠ {runError}</span>
          )}
        </div>

        <div className="btd-header-actions">
          <button type="button" className="btd-btn btd-btn--ghost" onClick={() => void fetchAll()}>새로고침</button>
          {tab === 'backtest' && (
            <button type="button" className="btd-btn btd-btn--danger" disabled={records.length === 0} onClick={() => void deleteAll()}>전체 삭제</button>
          )}
        </div>
      </header>

      <div className="btd-body">
        <aside className="btd-sidebar" style={{ width: leftWidth, flex: `0 0 ${leftWidth}px` }}>
          <BacktestExecutionList
            tab={tab}
            onTabChange={setTab}
            backtestRecords={records}
            liveItems={liveItems}
            selectedBacktestId={selectedBacktest?.id ?? null}
            selectedLiveId={selectedLive?.id ?? null}
            onSelectBacktest={r => { setSelectedBacktest(r); setTab('backtest'); }}
            onSelectLive={item => { setSelectedLive(item); setTab('live'); }}
          />
        </aside>

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

        <main className="btd-main">
          {centerHead && (
            <div className="btd-main-head">
              <h2 className="btd-main-ko">{centerHead.ko}</h2>
              <p className="btd-main-strategy">
                {centerHead.strategy}
                {centerHead.metaParts.length > 0 && (
                  <span className="btd-main-meta">
                    {' · '}
                    {centerHead.metaParts.filter(Boolean).join(' · ')}
                  </span>
                )}
              </p>
            </div>
          )}
          <div className="btd-main-content">
            {chartProps ? (
              <BacktestAnalysisChart
                symbol={chartProps.symbol}
                timeframe={chartProps.timeframe}
                toTimeSec={chartProps.toTimeSec}
                fromTimeSec={chartProps.fromTimeSec}
                barCount={chartProps.barCount}
                signals={activeSignals}
                strategyId={chartProps.strategyId}
                theme={theme}
                onOpenReport={() => setReportOpen(true)}
                reportDisabled={!reportModel}
              />
            ) : (
              <div className="btd-empty">
                <span>📈</span>
                <p>좌측 목록에서 분석할 실행 결과를 선택하세요.</p>
              </div>
            )}
          </div>

        </main>

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

        <aside className="btd-right" style={{ width: rightWidth, flex: `0 0 ${rightWidth}px` }}>
          <div className="btd-right-stack">
            <div className={`btd-right-section btd-right-section--kpi${showRightDetail ? '' : ' btd-right-section--solo'}`}>
              <BacktestKpiPanel
                analysis={tab === 'backtest' ? (backtestDetail?.analysis ?? null) : null}
                equityCurve={equityData.curve}
                totalReturnOverride={tab === 'live' && selectedLive ? selectedLive.totalReturnPct : undefined}
                winRateOverride={tab === 'live' && selectedLive ? selectedLive.winRatePct : undefined}
                tradeCountOverride={tab === 'live' && selectedLive ? selectedLive.tradeCount : undefined}
                mddOverride={tab === 'live' && selectedLive ? selectedLive.mddPct : undefined}
                sharpeOverride={tab === 'live' && selectedLive ? selectedLive.sharpeRatio : undefined}
                profitFactorOverride={tab === 'live' && selectedLive ? selectedLive.profitFactor : undefined}
                emptyText={tab === 'backtest' ? '백테스팅 결과를 선택하세요.' : '실시간 매매 결과를 선택하세요.'}
              />
            </div>
            {showRightDetail && (
              <div className="btd-right-section btd-right-section--trades">
                <BacktestTradeHistoryCard trades={footerTrades} />
              </div>
            )}
          </div>
        </aside>
      </div>

      <BacktestAnalysisReportModal
        open={reportOpen}
        onClose={() => setReportOpen(false)}
        model={reportModel}
      />
    </div>
  );
}

export default BacktestHistoryPage;
