import React, {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import {
  Alert,
  Box,
  Button,
  Chip,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  Grid,
  List,
  ListItemButton,
  ListItemText,
  ListSubheader,
  Pagination,
  Select,
  MenuItem,
  Stack,
  TextField,
  Typography,
} from '@mui/material';
import {
  applyStrategySettingsToUserspace,
  downloadStrategyPackage,
  fetchCapitalAllocationModeConfig,
  fetchStrategyList,
  fetchStrategySettings,
  fetchStrategyVersionDetail,
  fetchStrategyVersions,
  fetchSamplingStrategyConfig,
  fetchSimulationTemplateConfig,
  fetchSkipInvestmentWhenOptions,
  fetchMarketProfileOptions,
  restoreStrategyVersion,
  getStrategyDisplayLabel,
  getStrategyWorkbenchPath,
} from '../../api/apis/strategyApi';
import StrategyDescriptionText from '../../components/strategyDescriptionText/strategyDescriptionText';
import StrategyMetaDetailText from '../../components/strategyMetaDetailText/strategyMetaDetailText';
import StrategySettingsContainer from './panels/strategySettingsPanel/containers/strategySettingsContainer';
import {
  extractStrategyDescription,
  extractStrategyDisplayName,
  extractStrategyEntryConditions,
  normalizeMeta,
} from './panels/strategySettingsPanel/editorSchemas/strategyMeta';
import StrategyExecutionPanel from './panels/strategyExecutionPanel/strategyExecutionPanel';
import StrategyReportPanel from './panels/strategyReportPanel/strategyReportPanel';
import {
  buildWorkbenchExecutionHydrationFromSnapshot,
} from './workbenchExecutionHydration';
import {
  buildWorkbenchSnapshotFromSettingsResponse,
  buildWorkbenchSnapshotFromVersionDetail,
  emptyWorkbenchSnapshot,
} from './workbenchSnapshot';
import {
  PlaceholderSection,
  StrategySettingsPanel,
} from './panels/strategySettingsPanel/strategySettingsPanel';
import PageLayout from '../../components/pageLayout/pageLayout';
import PageLoadingState from '../../components/pageLoadingState/pageLoadingState';
import NtqIcon from '../../components/ntqIcon/ntqIcon';

/** 左侧草稿 settings 变更后重置右侧执行/报告（加载完成后首次对齐基线，之后任意变更触发 ``onReset``）。core 由容器在 keyup/粘贴时解析写入 ``draftSettings``，签名仅需序列化草稿。 */
function WorkbenchDraftChangeResetBridge({
  draftSettings,
  strategyName,
  isLoadingSettings,
  onReset,
  /** 下一次草稿签名变化来自服务端/容器同步（如恢复快照）时不触发右侧重置 */
  suppressDraftDrivenPanelResetRef,
}) {
  const baselineSigRef = useRef(null);
  const establishedRef = useRef(false);
  const compositeSig = JSON.stringify(draftSettings);

  useEffect(() => {
    if (!strategyName) return;
    if (isLoadingSettings) {
      establishedRef.current = false;
      baselineSigRef.current = null;
      return;
    }
    if (!establishedRef.current) {
      baselineSigRef.current = compositeSig;
      establishedRef.current = true;
      return;
    }
    if (compositeSig !== baselineSigRef.current) {
      baselineSigRef.current = compositeSig;
      if (suppressDraftDrivenPanelResetRef?.current) {
        suppressDraftDrivenPanelResetRef.current = false;
        return;
      }
      onReset();
    }
  }, [
    compositeSig,
    strategyName,
    isLoadingSettings,
    onReset,
    suppressDraftDrivenPanelResetRef,
  ]);

  return null;
}

/** 与执行面板「对比版本」下拉末项一致：打开完整版本列表 */
const RESTORE_MORE_MENU_VALUE = '__restore_more_versions__';
const VERSION_PICKER_PAGE_SIZE = 8;

/** 与 BFF ``workbench_latest_ui_flags.has_persisted_snapshot`` 一致：有效快照 id > 0 */
function versionDetailHasPersistedSnapshot(detail) {
  const vid = String(detail?.version_id ?? '').trim();
  if (!vid) return false;
  const n = Number(String(vid).replace(/^v/i, ''));
  return Number.isFinite(n) && n > 0;
}

/**
 * V2-08 单条快照 → 与 ``fetchStrategySettings``（V2-01）对齐的页面状态，避免恢复后再请求 ``version/latest``。
 * ``has_other_versions``：与后端「≥2 条快照」一致；恢复不写库时用已缓存的 ``GET …/versions`` 列表长度近似。
 */
function workbenchPageStateFromVersionDetail(detail, strategyName, cachedVersionRows) {
  const wbVer = typeof detail?.version_id === 'string' ? detail.version_id.trim() : '';
  const persisted = versionDetailHasPersistedSnapshot(detail);
  const rows = Array.isArray(cachedVersionRows) ? cachedVersionRows : [];
  const hasOtherVersions = persisted && rows.length >= 2;
  return {
    strategy_name: strategyName,
    settings: detail?.settings || {},
    workbench_version_id: wbVer,
    step_status: detail?.step_status,
    result_report: detail?.result_report ?? null,
    execution_panel: detail?.execution_panel ?? null,
    has_persisted_snapshot: persisted,
    has_other_versions: hasOtherVersions,
  };
}

function StrategyWorkbenchPage() {
  const navigate = useNavigate();
  const params = useParams();
  const strategyName = String(params['*'] || '').replace(/^\/+/, '');
  const [selectedConfigVersion, setSelectedConfigVersion] = useState('');
  const [configVersions, setConfigVersions] = useState([]);
  const [confirmOpen, setConfirmOpen] = useState(false);
  const [pendingVersionId, setPendingVersionId] = useState('');
  const [moreVersionsOpen, setMoreVersionsOpen] = useState(false);
  const [versionSearch, setVersionSearch] = useState('');
  const [versionPickerPage, setVersionPickerPage] = useState(1);
  const [strategyRows, setStrategyRows] = useState([]);
  const [strategyDescription, setStrategyDescription] = useState('');
  const [strategyEntryConditions, setStrategyEntryConditions] = useState([]);
  const [strategyDisplayName, setStrategyDisplayName] = useState('');
  const [pendingStrategyName, setPendingStrategyName] = useState('');
  const [switchStrategyConfirmOpen, setSwitchStrategyConfirmOpen] = useState(false);
  const [isLoadingSettings, setIsLoadingSettings] = useState(true);
  const [settingsError, setSettingsError] = useState('');
  const [isSavingSettings, setIsSavingSettings] = useState(false);
  const [saveError, setSaveError] = useState('');
  const [settingsOptionError, setSettingsOptionError] = useState('');
  const [allocationModeOptions, setAllocationModeOptions] = useState([]);
  const [samplingStrategyOptions, setSamplingStrategyOptions] = useState([]);
  const [simulationTemplateOptions, setSimulationTemplateOptions] = useState([]);
  const [simulationTemplateProfiles, setSimulationTemplateProfiles] = useState({});
  const [skipInvestmentWhenOptions, setSkipInvestmentWhenOptions] = useState([]);
  const [marketProfileOptions, setMarketProfileOptions] = useState([]);
  const [executionState, setExecutionState] = useState({
    stepStatus: {
      enum: 'idle',
      price: 'idle',
      capital: 'idle',
    },
    result: {
      enum: null,
      price: null,
      capital: null,
    },
    compareVersion: {
      enum: '',
      price: '',
      capital: '',
    },
    runningStep: '',
    runId: '',
    activeRunId: '',
    lastCompletedWorkbenchVersionId: '',
  });
  /** V2-01 / V2-08 工作台快照；执行/报告同源 */
  const [workbenchSnapshot, setWorkbenchSnapshot] = useState(() => emptyWorkbenchSnapshot());
  /** 与 ``mergeShapeOnly`` 合用的最小基底（仅 meta），不含任何示例策略字段 */
  const buildMergeBaseSettings = useCallback(() => ({
    is_enabled: false,
    meta: normalizeMeta({}),
  }), []);
  const [initialSettings, setInitialSettings] = useState(() => ({
    is_enabled: false,
    meta: normalizeMeta({}),
  }));

  const deepClone = (value) => JSON.parse(JSON.stringify(value));
  const mergeShapeOnly = useCallback((baseValue, incomingValue) => {
    if (Array.isArray(incomingValue)) return incomingValue;
    if (incomingValue && typeof incomingValue === 'object') {
      const out = {};
      const baseObj = baseValue && typeof baseValue === 'object' && !Array.isArray(baseValue) ? baseValue : {};
      const keys = new Set([
        ...Object.keys(baseObj || {}),
        ...Object.keys(incomingValue || {}),
      ]);
      keys.forEach((key) => {
        const next = incomingValue[key];
        if (next !== undefined) {
          out[key] = mergeShapeOnly(baseObj[key], next);
          return;
        }
        const base = baseObj[key];
        if (Array.isArray(base)) {
          out[key] = [];
        } else if (base && typeof base === 'object') {
          out[key] = mergeShapeOnly(base, {});
        }
      });
      return out;
    }
    return incomingValue;
  }, []);
  const [savedBaselineSettings, setSavedBaselineSettings] = useState(() => deepClone(initialSettings));
  const [appliedSettings, setAppliedSettings] = useState(() => deepClone(initialSettings));
  const [appliedVersionId, setAppliedVersionId] = useState('userspace');
  const [deployConfirmOpen, setDeployConfirmOpen] = useState(false);
  const [userspaceApplyOk, setUserspaceApplyOk] = useState('');
  /** 单步跑完后让「回测报告」 accordion 内 Tab 切到刚完成的回测步 */
  const reportTabFocusSeqRef = useRef(0);
  const [reportTabFocusRequest, setReportTabFocusRequest] = useState(null);
  /** V2-01 扩展：是否有 DB 快照、是否还有其它可对比版本（GET …/version/latest） */
  const [hasPersistedSnapshot, setHasPersistedSnapshot] = useState(false);
  const [hasOtherVersions, setHasOtherVersions] = useState(false);
  const lastRunSyncedVersionRef = useRef('');
  const snapshotSyncGenRef = useRef(0);
  /** 恢复快照等场景：草稿由容器跟随 ``initialSettings`` 替换，跳过一轮「草稿变更→清空右侧」 */
  const suppressDraftDrivenPanelResetRef = useRef(false);
  /** 草稿变更时递增，强制执行/报告面板 remount 清空内部 compare / 轮询等状态 */
  const [panelsResetEpoch, setPanelsResetEpoch] = useState(0);
  const [packageExporting, setPackageExporting] = useState(false);
  const [packageExportError, setPackageExportError] = useState('');

  const workbenchExecutionHydration = useMemo(() => {
    if (!workbenchSnapshot?.versionId) return null;
    return buildWorkbenchExecutionHydrationFromSnapshot(strategyName, workbenchSnapshot);
  }, [strategyName, workbenchSnapshot]);

  const resetPanelsAfterDraftChange = useCallback(() => {
    setPanelsResetEpoch((n) => n + 1);
    setWorkbenchSnapshot(emptyWorkbenchSnapshot());
    setSelectedConfigVersion('');
    setAppliedVersionId('userspace');
    lastRunSyncedVersionRef.current = '';
    setExecutionState({
      stepStatus: {
        enum: 'idle',
        price: 'idle',
        capital: 'idle',
      },
      result: {
        enum: null,
        price: null,
        capital: null,
      },
      compareVersion: {
        enum: '',
        price: '',
        capital: '',
      },
      runningStep: '',
      runId: '',
      activeRunId: '',
      lastCompletedWorkbenchVersionId: '',
    });
    setReportTabFocusRequest(null);
  }, []);

  const forceRunHandlersRef = useRef({ forceEnum: null });
  /** 与左侧表单 ``draftSettings`` 同步，供跑完后对齐 ``appliedSettings`` */
  const draftSettingsRef = useRef(null);

  const handleExportStrategyPackage = useCallback(async () => {
    if (!strategyName) return;
    setPackageExporting(true);
    setPackageExportError('');
    try {
      await downloadStrategyPackage(strategyName, { scope: 'bundle' });
    } catch (e) {
      setPackageExportError(e?.message || '导出失败');
    } finally {
      setPackageExporting(false);
    }
  }, [strategyName]);

  const handleRunStepComplete = useCallback((step) => {
    if (step !== 'enum' && step !== 'price' && step !== 'capital') return;
    reportTabFocusSeqRef.current += 1;
    setReportTabFocusRequest({ step, tick: reportTabFocusSeqRef.current });
    const draft = draftSettingsRef.current;
    if (draft && typeof draft === 'object') {
      setAppliedSettings(deepClone(draft));
    }
  }, []);

  const handleExecutionStateChange = useCallback((next) => {
    setExecutionState((prev) => {
      if (next.activeRunId && next.activeRunId !== prev.activeRunId) {
        lastRunSyncedVersionRef.current = '';
        snapshotSyncGenRef.current += 1;
      }
      return next;
    });
  }, []);

  /** 单步跑完：按 progress 的 ``version_id`` 拉 V2-08，顶栏摘要与报告读同一份快照 */
  useEffect(() => {
    if (!strategyName || isLoadingSettings) return undefined;
    const runVer = (executionState.lastCompletedWorkbenchVersionId || '').trim();
    if (!runVer) return undefined;
    if (runVer === lastRunSyncedVersionRef.current) return undefined;

    const syncGen = snapshotSyncGenRef.current;
    let cancelled = false;
    (async () => {
      try {
        const [detail, verRes] = await Promise.all([
          fetchStrategyVersionDetail(strategyName, runVer),
          fetchStrategyVersions(strategyName),
        ]);
        if (cancelled || syncGen !== snapshotSyncGenRef.current) return;
        const rows = (verRes?.versions || []).map((version) => ({
          id: version.version_id || `v${version.version || ''}`,
          createdAt: version.created_at || '',
          updatedAt: version.updated_at || '',
          version: Number(version.version || 0),
        }));
        const res = workbenchPageStateFromVersionDetail(detail, strategyName, rows);
        const wbVer = res.workbench_version_id || runVer;
        const snapshot = buildWorkbenchSnapshotFromVersionDetail(detail);
        setWorkbenchSnapshot(snapshot);
        const hydration = buildWorkbenchExecutionHydrationFromSnapshot(strategyName, snapshot);
        setExecutionState((prev) => ({
          ...prev,
          stepStatus: hydration.stepStatus,
          result: hydration.result,
          lastCompletedWorkbenchVersionId: wbVer,
        }));
        setConfigVersions(rows);
        setHasPersistedSnapshot(Boolean(res.has_persisted_snapshot));
        setHasOtherVersions(Boolean(res.has_other_versions));
        setSelectedConfigVersion(wbVer);
        setAppliedVersionId(wbVer);
        lastRunSyncedVersionRef.current = wbVer;
      } catch {
        /* 保留上一轮快照摘要；用户可切版本或刷新重试 */
      }
    })();

    return () => {
      cancelled = true;
    };
  }, [
    executionState.lastCompletedWorkbenchVersionId,
    isLoadingSettings,
    strategyName,
  ]);

  useEffect(() => {
    setSavedBaselineSettings(deepClone(initialSettings));
    setAppliedSettings(deepClone(initialSettings));
  }, [initialSettings]);

  useEffect(() => {
    fetchStrategyList()
      .then((res) => {
        setStrategyRows(res.data || []);
      })
      .catch(() => {
        setStrategyRows([]);
      });
  }, []);

  useEffect(() => {
    let cancelled = false;
    Promise.all([
      fetchCapitalAllocationModeConfig(),
      fetchSamplingStrategyConfig(),
      fetchSimulationTemplateConfig(),
      fetchSkipInvestmentWhenOptions(),
      fetchMarketProfileOptions(),
    ])
      .then(([allocationConfig, samplingConfig, simulationConfig, skipWhenOptions, marketProfiles]) => {
        if (cancelled) return;
        setAllocationModeOptions(allocationConfig?.options || []);
        setSamplingStrategyOptions(samplingConfig?.options || []);
        setSimulationTemplateOptions(simulationConfig?.options || []);
        setSimulationTemplateProfiles(simulationConfig?.profiles || {});
        setSkipInvestmentWhenOptions(skipWhenOptions || []);
        setMarketProfileOptions(marketProfiles || []);
        setSettingsOptionError('');
      })
      .catch((err) => {
        if (cancelled) return;
        setSettingsOptionError(err?.message || '读取设置选项失败，已使用默认值');
        setAllocationModeOptions([]);
        setSamplingStrategyOptions([]);
        setSimulationTemplateOptions([]);
        setSimulationTemplateProfiles({});
        setSkipInvestmentWhenOptions([]);
        setMarketProfileOptions([]);
      });
    return () => {
      cancelled = true;
    };
  }, []);

  useEffect(() => {
    let isCancelled = false;
    const mergeBase = buildMergeBaseSettings();

    if (!strategyName) {
      setConfigVersions([]);
      setSelectedConfigVersion('');
      setHasPersistedSnapshot(false);
      setHasOtherVersions(false);
      lastRunSyncedVersionRef.current = '';
      setInitialSettings({ is_enabled: false, meta: normalizeMeta({}) });
      setStrategyDisplayName('');
      setWorkbenchSnapshot(emptyWorkbenchSnapshot());
      setExecutionState({
        stepStatus: { enum: 'idle', price: 'idle', capital: 'idle' },
        result: { enum: null, price: null, capital: null },
        compareVersion: { enum: '', price: '', capital: '' },
        runningStep: '',
        runId: '',
        activeRunId: '',
        lastCompletedWorkbenchVersionId: '',
      });
      setStrategyDescription('');
      setStrategyEntryConditions([]);
      setIsLoadingSettings(false);
      setSettingsError('');
      return () => {
        isCancelled = true;
      };
    }

    setStrategyDescription('');
    setStrategyEntryConditions([]);
    setStrategyDisplayName('');
    setIsLoadingSettings(true);
    setSettingsError('');
    setWorkbenchSnapshot(emptyWorkbenchSnapshot());
    Promise.all([
      fetchStrategyVersions(strategyName),
      fetchStrategySettings(strategyName),
    ])
      .then(([verRes, res]) => {
        if (isCancelled) return;
        const rows = (verRes?.versions || []).map((version) => ({
          id: version.version_id || `v${version.version || ''}`,
          createdAt: version.created_at || '',
          updatedAt: version.updated_at || '',
          version: Number(version.version || 0),
        }));
        setConfigVersions(rows);
        setHasPersistedSnapshot(Boolean(res?.has_persisted_snapshot));
        setHasOtherVersions(Boolean(res?.has_other_versions));

        const serverSettings = res?.settings || {};
        const hasServerSettings = serverSettings && typeof serverSettings === 'object' && Object.keys(serverSettings).length > 0;
        const incomingMeta = (
          serverSettings?.meta && typeof serverSettings.meta === 'object'
            ? serverSettings.meta
            : {}
        );
        if (hasServerSettings) {
          const nextSettings = mergeShapeOnly(mergeBase, {
            ...serverSettings,
            meta: normalizeMeta(incomingMeta, serverSettings),
          });
          setInitialSettings(nextSettings);
          setStrategyDisplayName(
            extractStrategyDisplayName(nextSettings) || strategyName,
          );
          setStrategyDescription(extractStrategyDescription(nextSettings));
          setStrategyEntryConditions(extractStrategyEntryConditions(nextSettings));
          setSettingsError('');
        } else {
          setInitialSettings(mergeBase);
          setStrategyDescription('');
          setStrategyEntryConditions([]);
          setSettingsError('未返回有效策略配置（settings 为空）。');
        }
        const snapshot = buildWorkbenchSnapshotFromSettingsResponse(res);
        setWorkbenchSnapshot(snapshot);
        const hydration = buildWorkbenchExecutionHydrationFromSnapshot(strategyName, snapshot);
        setExecutionState({
          stepStatus: hydration.stepStatus,
          result: hydration.result,
          compareVersion: { enum: '', price: '', capital: '' },
          runningStep: '',
          runId: '',
          activeRunId: '',
          lastCompletedWorkbenchVersionId: hydration.lastCompletedWorkbenchVersionId,
        });
        lastRunSyncedVersionRef.current = hydration.lastCompletedWorkbenchVersionId;
        const wbVer = snapshot.versionId;
        setAppliedVersionId(wbVer !== '' ? wbVer : 'userspace');
        setSelectedConfigVersion(wbVer);
      })
      .catch((err) => {
        if (isCancelled) return;
        setInitialSettings(mergeBase);
        setHasPersistedSnapshot(false);
        setHasOtherVersions(false);
        lastRunSyncedVersionRef.current = '';
        setWorkbenchSnapshot(emptyWorkbenchSnapshot());
        setExecutionState({
          stepStatus: { enum: 'idle', price: 'idle', capital: 'idle' },
          result: { enum: null, price: null, capital: null },
          compareVersion: { enum: '', price: '', capital: '' },
          runningStep: '',
          runId: '',
          activeRunId: '',
          lastCompletedWorkbenchVersionId: '',
        });
        setConfigVersions([]);
        setSettingsError(err?.message || '读取策略配置失败');
      })
      .finally(() => {
        if (!isCancelled) setIsLoadingSettings(false);
      });

    return () => {
      isCancelled = true;
    };
  }, [buildMergeBaseSettings, mergeShapeOnly, strategyName]);

  const versionMap = useMemo(
    () => Object.fromEntries(configVersions.map((version) => [version.id, version])),
    [configVersions],
  );
  const latestFiveVersions = useMemo(() => configVersions.slice(0, 5), [configVersions]);
  /** 与执行器对比下拉一致：最近 5 条，且排除当前工作台快照（恢复自身无意义） */
  const restoreDropdownVersions = useMemo(() => {
    const cur = String(selectedConfigVersion || '').trim();
    return latestFiveVersions.filter((v) => !cur || v.id !== cur);
  }, [latestFiveVersions, selectedConfigVersion]);

  const versionPickerFiltered = useMemo(() => {
    const keyword = versionSearch.trim().toLowerCase();
    if (!keyword) return configVersions;
    return configVersions.filter((version) => (
      version.id.toLowerCase().includes(keyword)
      || version.createdAt.toLowerCase().includes(keyword)
      || version.updatedAt.toLowerCase().includes(keyword)
    ));
  }, [configVersions, versionSearch]);

  const versionPickerTotalPages = Math.max(
    1,
    Math.ceil(versionPickerFiltered.length / VERSION_PICKER_PAGE_SIZE) || 1,
  );

  const versionPickerSlice = useMemo(() => {
    const page = Math.min(versionPickerPage, versionPickerTotalPages);
    const start = (page - 1) * VERSION_PICKER_PAGE_SIZE;
    return versionPickerFiltered.slice(start, start + VERSION_PICKER_PAGE_SIZE);
  }, [versionPickerFiltered, versionPickerPage, versionPickerTotalPages]);

  useEffect(() => {
    setVersionPickerPage(1);
  }, [versionSearch]);

  useEffect(() => {
    setVersionPickerPage((p) => Math.min(p, versionPickerTotalPages));
  }, [versionPickerTotalPages]);

  const requestApplyVersion = (versionId) => {
    if (!versionId) return;
    setPendingVersionId(versionId);
    setConfirmOpen(true);
  };

  const openMoreVersionsDialog = () => {
    setSaveError('');
    setUserspaceApplyOk('');
    setVersionPickerPage(1);
    setMoreVersionsOpen(true);
  };

  const handleRestoreMenuChange = (event) => {
    const value = event.target.value;
    const proceed = () => {
      if (value === RESTORE_MORE_MENU_VALUE) {
        openMoreVersionsDialog();
        return;
      }
      if (value) {
        setSaveError('');
        setUserspaceApplyOk('');
        requestApplyVersion(value);
      }
    };
    window.setTimeout(proceed, 0);
  };

  const closeVersionsDialog = () => {
    setMoreVersionsOpen(false);
    setVersionSearch('');
    setVersionPickerPage(1);
  };

  const bannerDescription = useMemo(() => (
    <StrategyMetaDetailText
      description={strategyDescription}
      entryConditions={strategyEntryConditions}
      variant="body2"
      color="text.secondary"
      empty=""
    />
  ), [strategyDescription, strategyEntryConditions]);

  return (
    <PageLayout
      className="strategy-workbench-page"
      breadcrumbsItems={[
        { label: '策略实验室', to: '/strategy-workbench' },
        { label: '选择策略', to: '/strategy-workbench' },
      ]}
      breadcrumbsCurrent={
        strategyDisplayName || strategyName
          ? `调试：${strategyDisplayName || strategyName}`
          : '策略调试'
      }
      bannerTitle={
        strategyDisplayName || strategyName
          ? `调试：${strategyDisplayName || strategyName}`
          : '策略调试'
      }
      bannerDescription={bannerDescription}
      bannerRightSlot={
        strategyName ? (
          <Button
            variant="outlined"
            size="small"
            onClick={handleExportStrategyPackage}
            disabled={packageExporting}
            className="ntq-glass-outline-btn"
            startIcon={<NtqIcon name="download" size={22} tone="muted" />}
          >
            {packageExporting ? '导出中…' : '导出策略包'}
          </Button>
        ) : null
      }
    >
      {packageExportError ? (
        <Alert severity="error" sx={{ mb: 2 }} onClose={() => setPackageExportError('')}>
          {packageExportError}
        </Alert>
      ) : null}
      {isLoadingSettings && strategyName ? (
        <PageLoadingState message="正在加载策略配置…" minHeight="min(52vh, 520px)" />
      ) : null}
      {!(isLoadingSettings && strategyName) ? (
      <StrategySettingsContainer initialSettings={initialSettings}>
        {({
          draftSettings,
          setDraftSettings,
          coreEditor,
          onGoalChange,
          onSamplingChange,
          onFeesChange,
          onSimulationChange,
          onPriceSimulatorChange,
          onCapitalSimulatorChange,
        }) => (
          <>
            {(() => {
              const hasUnsavedChanges = JSON.stringify(draftSettings) !== JSON.stringify(savedBaselineSettings);
              const isAppliedSettings = JSON.stringify(draftSettings) === JSON.stringify(appliedSettings);
              const workspaceVersionLabel = selectedConfigVersion || '（尚无快照）';
              const currentVersionDisplay =
                appliedVersionId === 'userspace'
                  ? 'settings文件'
                  : String(appliedVersionId || '').trim() || workspaceVersionLabel;
              const visibleStrategies = strategyRows.filter((row) => row?.name && row.name !== strategyName);
              const disableSettingsActions = isSavingSettings || isLoadingSettings || !strategyName;
              const getDraftSettingsForSubmit = () => (
                coreEditor?.getDraftSettingsForSubmit
                  ? coreEditor.getDraftSettingsForSubmit()
                  : draftSettings
              );
              draftSettingsRef.current = draftSettings;

              const requestSwitchStrategy = (nextStrategyName) => {
                if (!nextStrategyName) return;
                if (hasUnsavedChanges) {
                  setPendingStrategyName(nextStrategyName);
                  setSwitchStrategyConfirmOpen(true);
                  return;
                }
                navigate(getStrategyWorkbenchPath(nextStrategyName));
              };

              return (
                <>
            <WorkbenchDraftChangeResetBridge
              key={strategyName || ''}
              draftSettings={draftSettings}
              strategyName={strategyName}
              isLoadingSettings={isLoadingSettings}
              onReset={resetPanelsAfterDraftChange}
              suppressDraftDrivenPanelResetRef={suppressDraftDrivenPanelResetRef}
            />
            <Box
              sx={{
                mb: 2,
                display: 'flex',
                flexDirection: 'column',
                gap: 1.5,
              }}
            >
              {settingsError ? (
                <Typography variant="body2" color="error">
                  无法加载策略配置：{settingsError}
                </Typography>
              ) : null}
              {saveError ? (
                <Typography variant="body2" color="error">
                  保存失败：{saveError}
                </Typography>
              ) : null}
              {settingsOptionError ? (
                <Typography variant="body2" color="warning.main">
                  选项加载提示：{settingsOptionError}
                </Typography>
              ) : null}
              {userspaceApplyOk ? (
                <Typography variant="body2" color="success.main">
                  {userspaceApplyOk}
                </Typography>
              ) : null}

              {hasPersistedSnapshot ? (
              <Box
                sx={{
                  p: 1.5,
                  border: 1,
                  borderColor: 'divider',
                  borderRadius: 1,
                  backgroundColor: 'background.paper',
                }}
              >
                <Stack spacing={1}>
                  <Box
                    sx={{
                      display: 'flex',
                      flexDirection: { xs: 'column', md: 'row' },
                      alignItems: { xs: 'stretch', md: 'center' },
                      justifyContent: 'space-between',
                      gap: 1,
                    }}
                  >
                    <Stack direction={{ xs: 'column', md: 'row' }} spacing={1} alignItems={{ xs: 'flex-start', md: 'center' }}>
                      <Typography variant="body2">当前版本：<strong>{currentVersionDisplay}</strong></Typography>
                      {isAppliedSettings ? (
                        <Chip size="small" color="success" label="无设置变化" />
                      ) : (
                        <Chip
                          size="small"
                          color="warning"
                          label="发现设置变化，执行任意回测后将会产生新版本"
                          sx={{
                            height: 'auto',
                            py: 0.5,
                            maxWidth: { xs: '100%', md: 360 },
                            '& .MuiChip-label': {
                              whiteSpace: 'normal',
                              lineHeight: 1.35,
                              textAlign: 'left',
                            },
                          }}
                        />
                      )}
                    </Stack>
                    <Stack direction={{ xs: 'column', sm: 'row' }} spacing={1} justifyContent={{ xs: 'stretch', md: 'flex-end' }}>
                      {hasOtherVersions ? (
                        <Select
                          size="small"
                          displayEmpty
                          value=""
                          renderValue={() => '恢复到版本…'}
                          onChange={handleRestoreMenuChange}
                          disabled={disableSettingsActions}
                          sx={{ minWidth: 168 }}
                          className="ntq-compact-dropdown"
                        >
                          <ListSubheader disableSticky>
                            恢复到版本…
                          </ListSubheader>
                          {restoreDropdownVersions.map((version) => (
                            <MenuItem key={version.id} value={version.id}>{version.id}</MenuItem>
                          ))}
                          <MenuItem value={RESTORE_MORE_MENU_VALUE}>更多版本…</MenuItem>
                        </Select>
                      ) : null}
                      <Button
                        variant="contained"
                        size="small"
                        disabled={disableSettingsActions}
                        onClick={() => {
                          setSaveError('');
                          setUserspaceApplyOk('');
                          setDeployConfirmOpen(true);
                        }}
                      >
                        应用当前工作台版本到策略
                      </Button>
                    </Stack>
                  </Box>
                </Stack>
              </Box>
              ) : null}
            </Box>
            <Grid container spacing={2}>
              <Grid item xs={12} md={3}>
              <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>
                <StrategySettingsPanel
                  settings={draftSettings}
                  onSettingsChange={setDraftSettings}
                  coreEditor={coreEditor}
                  allocationModeOptions={allocationModeOptions}
                  samplingStrategyOptions={samplingStrategyOptions}
                  simulationTemplateOptions={simulationTemplateOptions}
                  simulationTemplateProfiles={simulationTemplateProfiles}
                  skipInvestmentWhenOptions={skipInvestmentWhenOptions}
                  marketProfileOptions={marketProfileOptions}
                  onGoalChange={onGoalChange}
                  onSamplingChange={onSamplingChange}
                  onFeesChange={onFeesChange}
                  onSimulationChange={onSimulationChange}
                  onPriceSimulatorChange={onPriceSimulatorChange}
                  onCapitalSimulatorChange={onCapitalSimulatorChange}
                />
                <PlaceholderSection
                  title="其他策略"
                >
                  {visibleStrategies.length > 0 ? (
                    <List dense disablePadding>
                      {visibleStrategies.map((row) => (
                        <ListItemButton key={row.id} onClick={() => requestSwitchStrategy(row.name)}>
                          <ListItemText
                            primary={getStrategyDisplayLabel(row)}
                            secondary={(
                              <StrategyDescriptionText
                                text={row.description}
                                variant="caption"
                                color="text.secondary"
                                empty=""
                                maxLines={2}
                                component="span"
                              />
                            )}
                          />
                        </ListItemButton>
                      ))}
                    </List>
                  ) : (
                    <Typography variant="body2" color="text.secondary">
                      暂无其他策略。
                    </Typography>
                  )}
                </PlaceholderSection>
              </Box>
              </Grid>
              <Grid item xs={12} md={9}>
                <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>
                  <StrategyExecutionPanel
                    key={`exec-${strategyName || ''}-${panelsResetEpoch}`}
                    strategyName={strategyName}
                    settings={draftSettings}
                    getSettingsForRun={getDraftSettingsForSubmit}
                    onExecutionStateChange={handleExecutionStateChange}
                    executionCompareRecentVersionIds={latestFiveVersions.map((v) => v.id)}
                    onRunStepComplete={handleRunStepComplete}
                    workbenchHydration={workbenchExecutionHydration}
                    onRegisterForceHandlers={(api) => {
                      forceRunHandlersRef.current = api || {};
                    }}
                    showVersionCompare={hasOtherVersions}
                    configVersions={configVersions}
                  />
                  <StrategyReportPanel
                    key={`report-${strategyName || ''}-${panelsResetEpoch}`}
                    strategyName={strategyName}
                    executionState={executionState}
                    executionCompareRecentVersionIds={latestFiveVersions.map((v) => v.id)}
                    configVersions={configVersions}
                    workbenchSnapshot={workbenchSnapshot}
                    reportTabFocusRequest={reportTabFocusRequest}
                    onForceEnumerate={() => forceRunHandlersRef.current?.forceEnum?.()}
                    showReportCompare={hasOtherVersions}
                  />
                </Box>
              </Grid>
            </Grid>

            <Dialog open={deployConfirmOpen} onClose={() => setDeployConfirmOpen(false)} maxWidth="xs" fullWidth>
              <DialogTitle>发布到策略目录</DialogTitle>
              <DialogContent dividers>
                <Typography variant="body2">
                  将把当前工作台参数写入该策略在 userspace 下的 settings.py，覆盖目录中的现有文件。
                  此操作不会改动 DB 中的工作台快照（快照仍通过保存/执行步骤累积）。
                </Typography>
              </DialogContent>
              <DialogActions>
                <Button onClick={() => setDeployConfirmOpen(false)}>取消</Button>
                <Button
                  variant="contained"
                  disabled={isSavingSettings}
                  onClick={() => {
                    if (!strategyName) {
                      setDeployConfirmOpen(false);
                      return;
                    }
                    setIsSavingSettings(true);
                    setSaveError('');
                    applyStrategySettingsToUserspace(strategyName, getDraftSettingsForSubmit())
                      .then(() => {
                        setUserspaceApplyOk('已写入 userspace 策略 settings.py。');
                        setDeployConfirmOpen(false);
                      })
                      .catch((err) => {
                        setSaveError(err?.message || '发布到策略目录失败');
                      })
                      .finally(() => {
                        setIsSavingSettings(false);
                      });
                  }}
                >
                  {isSavingSettings ? '发布中...' : '确认发布'}
                </Button>
              </DialogActions>
            </Dialog>

            <Dialog open={confirmOpen} onClose={() => setConfirmOpen(false)} maxWidth="xs" fullWidth>
              <DialogTitle>恢复历史快照到工作台</DialogTitle>
              <DialogContent dividers>
                <Typography variant="body2">
                  将把快照
                  {' '}
                  <strong>{pendingVersionId}</strong>
                  {' '}
                  恢复为当前工作台内容（写入 DB 新快照，不修改 userspace 下的 settings.py）。
                  未保存的草稿将被覆盖。
                </Typography>
              </DialogContent>
              <DialogActions>
                <Button onClick={() => setConfirmOpen(false)}>取消</Button>
                <Button
                  variant="contained"
                  disabled={isSavingSettings}
                  onClick={() => {
                    const target = versionMap[pendingVersionId];
                    if (!target || !strategyName) {
                      setConfirmOpen(false);
                      return;
                    }
                    setIsSavingSettings(true);
                    setSaveError('');
                    restoreStrategyVersion(strategyName, target.id)
                      .then((restoreMeta) => {
                        suppressDraftDrivenPanelResetRef.current = true;
                        const detail = restoreMeta.detail;
                        const res = workbenchPageStateFromVersionDetail(
                          detail,
                          strategyName,
                          configVersions,
                        );
                        setHasPersistedSnapshot(Boolean(res?.has_persisted_snapshot));
                        setHasOtherVersions(Boolean(res?.has_other_versions));
                        const snapshot = buildWorkbenchSnapshotFromVersionDetail(detail);
                        setWorkbenchSnapshot(snapshot);
                        const wbVerRestore = snapshot.versionId;
                        lastRunSyncedVersionRef.current = wbVerRestore;
                        const hydrationRestore = buildWorkbenchExecutionHydrationFromSnapshot(
                          strategyName,
                          snapshot,
                        );
                        hydrationRestore.key = `${strategyName}:${wbVerRestore || String(restoreMeta?.version_id || 'restore')}`;
                        setExecutionState({
                          stepStatus: hydrationRestore.stepStatus,
                          result: hydrationRestore.result,
                          compareVersion: { enum: '', price: '', capital: '' },
                          runningStep: '',
                          runId: '',
                          activeRunId: '',
                          lastCompletedWorkbenchVersionId: wbVerRestore,
                        });
                        const serverSettings = res?.settings || {};
                        const incomingMeta = (
                          serverSettings?.meta && typeof serverSettings.meta === 'object'
                            ? serverSettings.meta
                            : {
                              name: serverSettings?.name,
                              description: serverSettings?.description,
                              is_enabled: serverSettings?.is_enabled,
                            }
                        );
                        const mergedSettings = mergeShapeOnly(buildMergeBaseSettings(), {
                          ...serverSettings,
                          meta: normalizeMeta({
                            ...incomingMeta,
                            name: strategyName,
                          }),
                        });
                        const wb = wbVerRestore || restoreMeta?.version_id || '';
                        setInitialSettings(mergedSettings);
                        setStrategyDescription(extractStrategyDescription(mergedSettings));
                        setStrategyEntryConditions(extractStrategyEntryConditions(mergedSettings));
                        setDraftSettings(deepClone(mergedSettings));
                        setSelectedConfigVersion(wb);
                        setSavedBaselineSettings(deepClone(mergedSettings));
                        setAppliedSettings(deepClone(mergedSettings));
                        setAppliedVersionId(
                          typeof wb === 'string' && wb.trim() !== '' ? wb.trim() : 'userspace',
                        );
                        setConfirmOpen(false);
                      })
                      .catch((err) => {
                        setSaveError(err?.message || '恢复快照失败');
                      })
                      .finally(() => {
                        setIsSavingSettings(false);
                      });
                  }}
                >
                  {isSavingSettings ? '处理中...' : '确认恢复'}
                </Button>
              </DialogActions>
            </Dialog>

            <Dialog open={moreVersionsOpen} onClose={closeVersionsDialog} maxWidth="sm" fullWidth>
              <DialogTitle>选择工作台版本</DialogTitle>
              <DialogContent dividers>
                <Stack spacing={1}>
                  <TextField
                    size="small"
                    fullWidth
                    placeholder="搜索版本 ID、创建或更新时间"
                    value={versionSearch}
                    onChange={(event) => setVersionSearch(event.target.value)}
                  />
                  <Typography variant="caption" color="text.secondary">
                    {configVersions.length > 0
                      ? `共 ${versionPickerFiltered.length} 条${versionPickerFiltered.length !== configVersions.length ? `（已筛选，全部 ${configVersions.length} 条）` : ''}`
                      : '暂无可选版本'}
                  </Typography>
                  <List sx={{ maxHeight: 340, overflow: 'auto', border: 1, borderColor: 'divider', borderRadius: 1 }}>
                    {versionPickerSlice.length > 0 ? versionPickerSlice.map((version) => (
                      <ListItemButton
                        key={version.id}
                        selected={version.id === selectedConfigVersion}
                        onClick={() => {
                          closeVersionsDialog();
                          requestApplyVersion(version.id);
                        }}
                      >
                        <ListItemText
                          primary={version.id}
                          secondary={version.updatedAt || version.createdAt}
                        />
                      </ListItemButton>
                    )) : (
                      <Box sx={{ p: 1.5 }}>
                        <Typography variant="body2" color="text.secondary">
                          {configVersions.length > 0 ? '没有匹配的版本。' : '暂无可应用的工作台版本。'}
                        </Typography>
                      </Box>
                    )}
                  </List>
                  {versionPickerFiltered.length > VERSION_PICKER_PAGE_SIZE ? (
                    <Box sx={{ display: 'flex', justifyContent: 'center', pt: 0.5 }}>
                      <Pagination
                        count={versionPickerTotalPages}
                        page={Math.min(versionPickerPage, versionPickerTotalPages)}
                        onChange={(_event, nextPage) => setVersionPickerPage(nextPage)}
                        size="small"
                        color="primary"
                      />
                    </Box>
                  ) : null}
                </Stack>
              </DialogContent>
              <DialogActions>
                <Button onClick={closeVersionsDialog}>关闭</Button>
              </DialogActions>
            </Dialog>
            <Dialog
              open={switchStrategyConfirmOpen}
              onClose={() => setSwitchStrategyConfirmOpen(false)}
              maxWidth="xs"
              fullWidth
            >
              <DialogTitle>存在未保存修改</DialogTitle>
              <DialogContent dividers>
                <Typography variant="body2">
                  当前参数有未保存修改。确定切换到
                  {' '}
                  <strong>{pendingStrategyName}</strong>
                  {' '}
                  吗？未保存内容将丢失。
                </Typography>
              </DialogContent>
              <DialogActions>
                <Button onClick={() => setSwitchStrategyConfirmOpen(false)}>取消</Button>
                <Button
                  variant="contained"
                  onClick={() => {
                    const next = pendingStrategyName;
                    setSwitchStrategyConfirmOpen(false);
                    setPendingStrategyName('');
                    if (next) navigate(getStrategyWorkbenchPath(next));
                  }}
                >
                  确认切换
                </Button>
              </DialogActions>
            </Dialog>
          </>
              );
            })()}
          </>
        )}
      </StrategySettingsContainer>
      ) : null}
    </PageLayout>
  );
}

export default StrategyWorkbenchPage;
