/**
 * 차트 우측 세로 툴바 — 캔들·보조지표 pane 과 높이 동기화.
 * pane 하단: 드래그 핸들 + 펼침메뉴(분리·복사·전체보기·종료)
 */
import React, { useState, useEffect, useCallback, useRef } from 'react';
import { createPortal } from 'react-dom';
import type { IndicatorConfig } from '../types';
import { ChartManager } from '../utils/ChartManager';
import { getPaneHostId } from '../utils/indicatorPaneMerge';
import { isIndicatorPaneFocused, resolveFocusedPaneLayoutId } from '../utils/indicatorPaneFocus';
import { buildPaneItems, resolvePaneItemLayout } from './paneLegendLayout';
import type { ChartOverlayToggleKey } from '../utils/chartOverlayVisibility';

export interface CandleOverlayToggleItem {
  key:     ChartOverlayToggleKey;
  label:   string;
  visible: boolean;
}

export interface ChartRightToolbarProps {
  manager:     ChartManager;
  indicators:  IndicatorConfig[];
  chartHeight: number;
  paused?:     boolean;
  /** 캔들 pane 상단 — 이동평균·일목·볼린저 표시/숨김 (투자관리 차트 탭) */
  candleOverlayToggles?: CandleOverlayToggleItem[];
  onToggleCandleOverlay?: (key: ChartOverlayToggleKey) => void;
  onSplit?:    (hostId: string) => void;
  onRemove?:   (id: string) => void;
  onDuplicate?: (id: string) => void;
  onExpand?:   (id: string) => void;
  onRestore?:  () => void;
  focusedId?:  string | null;
  onDragStart?: (id: string, e: React.PointerEvent) => void;
  /** 지표명 툴바 — 표시/숨기기 */
  onToggleHidden?: (id: string) => void;
  /** 지표명 툴바 — 설정 모달 */
  onSettings?: (id: string) => void;
  /** Custom / Custom1 오버레이 — 적용 여부 (동시 적용 불가, 설정은 슬롯별 분리) */
  customOverlayActive?: boolean;
  onCustomOverlayActiveChange?: (active: boolean) => void;
  onOpenCustomOverlaySettings?: () => void;
  custom1OverlayActive?: boolean;
  onCustom1OverlayActiveChange?: (active: boolean) => void;
  onOpenCustom1OverlaySettings?: () => void;
  /** true — 캔들 pane 상단 오버레이 토글만 (미니 차트 등) */
  overlayControlsOnly?: boolean;
  /** 9·20일 신고가·신저가 라벨 표시 (실시간 차트) */
  priceExtremeLabelsVisible?: boolean;
  onTogglePriceExtremeLabels?: () => void;
}

const BTN_SIZE = 32;
const BTN_GAP  = 2;

const IconCopy = () => (
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none"
    stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
    <rect x="4.5" y="1.5" width="8" height="8" rx="1"/>
    <path d="M1.5 4.5v8h8"/>
  </svg>
);

const IconSplit = () => (
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none"
    stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <polyline points="1,7 5,3 5,11"/>
    <polyline points="13,7 9,3 9,11"/>
    <line x1="5" y1="7" x2="9" y2="7"/>
  </svg>
);

const IconClose = () => (
  <svg width="12" height="12" viewBox="0 0 11 11" fill="none"
    stroke="currentColor" strokeWidth="2" strokeLinecap="round">
    <line x1="1.5" y1="1.5" x2="9.5" y2="9.5"/>
    <line x1="9.5" y1="1.5" x2="1.5" y2="9.5"/>
  </svg>
);

const IconExpand = () => (
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none"
    stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <polyline points="1,9 1,13 5,13"/>
    <line x1="1" y1="13" x2="5.5" y2="8.5"/>
    <polyline points="13,5 13,1 9,1"/>
    <line x1="13" y1="1" x2="8.5" y2="5.5"/>
  </svg>
);

const IconRestore = () => (
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none"
    stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <polyline points="5,13 1,13 1,9"/>
    <line x1="1" y1="13" x2="5.5" y2="8.5"/>
    <polyline points="9,1 13,1 13,5"/>
    <line x1="13" y1="1" x2="8.5" y2="5.5"/>
  </svg>
);

const IconDrag = () => (
  <svg width="10" height="14" viewBox="0 0 10 14" fill="currentColor">
    <circle cx="2.5" cy="2.5"  r="1.5"/>
    <circle cx="7.5" cy="2.5"  r="1.5"/>
    <circle cx="2.5" cy="7"    r="1.5"/>
    <circle cx="7.5" cy="7"    r="1.5"/>
    <circle cx="2.5" cy="11.5" r="1.5"/>
    <circle cx="7.5" cy="11.5" r="1.5"/>
  </svg>
);

const IconMore = () => (
  <svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor">
    <circle cx="7" cy="3"   r="1.3"/>
    <circle cx="7" cy="7"   r="1.3"/>
    <circle cx="7" cy="11"  r="1.3"/>
  </svg>
);

const IconMa = () => (
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none"
    stroke="currentColor" strokeWidth="1.8" strokeLinecap="round">
    <path d="M1 10 L5 4 L8 7 L13 2"/>
  </svg>
);

const IconBollinger = () => (
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none"
    stroke="currentColor" strokeWidth="1.4" strokeLinecap="round">
    <path d="M1 4 Q7 1 13 4"/>
    <path d="M1 7 Q7 4 13 7"/>
    <path d="M1 10 Q7 13 13 10"/>
  </svg>
);

const IconCandle = () => (
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none"
    stroke="currentColor" strokeWidth="1.6" strokeLinecap="round">
    <line x1="4" y1="2" x2="4" y2="12"/>
    <rect x="2.5" y="5" width="3" height="4" rx="0.5" fill="currentColor" stroke="none"/>
    <line x1="10" y1="3" x2="10" y2="11"/>
    <rect x="8.5" y="4" width="3" height="5" rx="0.5" fill="currentColor" stroke="none"/>
  </svg>
);

const IconIchimoku = () => (
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none"
    stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round">
    <path d="M1 9 L7 5 L13 9" fill="rgba(239,83,80,0.25)"/>
    <path d="M1 5 L7 9 L13 5" fill="rgba(38,166,154,0.25)"/>
    <path d="M1 9 L7 5 L13 9"/>
    <path d="M1 5 L7 9 L13 5"/>
  </svg>
);

/** 신고가(상향)·신저가(하향) */
const IconPriceExtreme = () => (
  <svg width="14" height="14" viewBox="0 0 14 14" aria-hidden>
    <path d="M7 1.5 L10.5 6 H3.5 Z" fill="#4dabf7"/>
    <path d="M7 12.5 L3.5 8 H10.5 Z" fill="#ef5350"/>
  </svg>
);

const OVERLAY_ICONS: Record<ChartOverlayToggleKey, React.ReactNode> = {
  ma: <IconMa />,
  bollinger: <IconBollinger />,
  ichimoku: <IconIchimoku />,
  candle: <IconCandle />,
};

const IconEye = ({ hidden }: { hidden?: boolean }) => hidden ? (
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="1.5">
    <path d="M1 7 Q4 2.5 7 2.5 Q10 2.5 13 7 Q10 11.5 7 11.5 Q4 11.5 1 7 Z" strokeOpacity="0.35"/>
    <line x1="2" y1="2" x2="12" y2="12"/>
  </svg>
) : (
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="1.5">
    <path d="M1 7 Q4 2.5 7 2.5 Q10 2.5 13 7 Q10 11.5 7 11.5 Q4 11.5 1 7 Z"/>
    <circle cx="7" cy="7" r="2"/>
  </svg>
);

const CUSTOM_MENU_ID = '__custom_overlay__';
const CUSTOM1_MENU_ID = '__custom1_overlay__';

const IconCustom = () => (
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none"
    stroke="currentColor" strokeWidth="1.5" strokeLinecap="round">
    <path d="M2 4h10M2 7h10M2 10h6"/>
    <circle cx="10.5" cy="10" r="1.2" fill="currentColor" stroke="none"/>
  </svg>
);

const IconCheck = () => (
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none"
    stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <polyline points="2,7.5 5.5,11 12,3"/>
  </svg>
);

const IconGear = () => (
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="1.4">
    <circle cx="7" cy="7" r="2.3"/>
    <path d="M7 1 L7.7 2.8 L9.8 2 L9.8 4.2 L11.8 5 L11 7 L11.8 9 L9.8 9.8 L9.8 12 L7.7 11.2 L7 13 L6.3 11.2 L4.2 12 L4.2 9.8 L2.2 9 L3 7 L2.2 5 L4.2 4.2 L4.2 2 L6.3 2.8 Z"/>
  </svg>
);

const CustomOverlayFlyoutMenu: React.FC<{
  title: string;
  flyoutPos: { top: number; left: number };
  overlayActive: boolean;
  onToggleActive: () => void;
  onOpenSettings: () => void;
  onCancelClose: () => void;
  onScheduleClose: () => void;
  onCloseFlyout: () => void;
}> = ({
  title,
  flyoutPos,
  overlayActive,
  onToggleActive,
  onOpenSettings,
  onCancelClose,
  onScheduleClose,
  onCloseFlyout,
}) => createPortal(
  <div
    className="tv-side-flyout tv-side-flyout--right-anchor tv-side-flyout--custom-overlay"
    style={{ top: flyoutPos.top, left: flyoutPos.left }}
    onMouseEnter={onCancelClose}
    onMouseLeave={onScheduleClose}
  >
    <div className="tv-side-flyout-header">{title}</div>
    <button
      type="button"
      className={`tv-side-flyout-item${overlayActive ? ' active' : ''}`}
      onClick={e => {
        e.stopPropagation();
        onToggleActive();
        onCloseFlyout();
      }}
    >
      <span className="tv-side-flyout-icon"><IconCheck /></span>
      <span className="tv-side-flyout-title">
        {overlayActive ? '미적용' : '적용'}
      </span>
    </button>
    <button
      type="button"
      className="tv-side-flyout-item"
      onClick={e => {
        e.stopPropagation();
        onOpenSettings();
        onCloseFlyout();
      }}
    >
      <span className="tv-side-flyout-icon"><IconGear /></span>
      <span className="tv-side-flyout-title">설정</span>
    </button>
  </div>,
  document.body,
);

interface MenuItemDef {
  key: string;
  title: string;
  icon: React.ReactNode;
  active?: boolean;
  danger?: boolean;
  onClick: () => void;
}

function buildMenuItems(
  item: ReturnType<typeof buildPaneItems>[number],
  indicators: IndicatorConfig[],
  paneItems: ReturnType<typeof buildPaneItems>,
  opts: {
    focusedId?: string | null;
    onSplit?: (hostId: string) => void;
    onDuplicate?: (id: string) => void;
    onExpand?: (id: string) => void;
    onRestore?: () => void;
    onRemove?: (id: string) => void;
    onToggleHidden?: (id: string) => void;
    onSettings?: (id: string) => void;
    onDone?: () => void;
  },
): MenuItemDef[] {
  const samePaneItems = paneItems.filter(p => p.paneIndex === item.paneIndex);
  const itemHostId = getPaneHostId(item.id, indicators);
  const isMergedPane = samePaneItems.length > 1;
  const showSplit = isMergedPane && item.id === itemHostId && !!opts.onSplit;
  const isFocused = isIndicatorPaneFocused(item.id, opts.focusedId, indicators);
  const showExpand = !!(opts.onExpand || (opts.focusedId && opts.onRestore));
  const done = opts.onDone ?? (() => {});
  const cfg = indicators.find(ind => ind.id === item.id);
  const isHidden = cfg?.hidden === true;

  const items: MenuItemDef[] = [];

  if (opts.onToggleHidden) {
    items.push({
      key: 'visibility',
      title: isHidden ? '표시' : '숨기기',
      icon: <IconEye hidden={isHidden} />,
      active: isHidden,
      onClick: () => { opts.onToggleHidden?.(item.id); done(); },
    });
  }
  if (opts.onSettings) {
    items.push({
      key: 'settings',
      title: '지표 설정',
      icon: <IconGear />,
      onClick: () => { opts.onSettings?.(item.id); done(); },
    });
  }
  if (showSplit) {
    items.push({
      key: 'split',
      title: '보조지표 분리',
      icon: <IconSplit />,
      onClick: () => { opts.onSplit?.(itemHostId); done(); },
    });
  }
  if (opts.onDuplicate) {
    items.push({
      key: 'copy',
      title: '보조지표 복사',
      icon: <IconCopy />,
      onClick: () => { opts.onDuplicate?.(item.id); done(); },
    });
  }
  if (showExpand) {
    items.push({
      key: 'expand',
      title: isFocused ? '전체 보기로 복원' : '이 지표만 보기',
      icon: isFocused ? <IconRestore /> : <IconExpand />,
      active: isFocused,
      onClick: () => {
        if (isFocused) opts.onRestore?.();
        else opts.onExpand?.(item.id);
        done();
      },
    });
  }
  if (opts.onRemove) {
    items.push({
      key: 'remove',
      title: '지표 제거',
      icon: <IconClose />,
      danger: true,
      onClick: () => { opts.onRemove?.(item.id); done(); },
    });
  }

  return items;
}

const ChartRightToolbar: React.FC<ChartRightToolbarProps> = ({
  manager, indicators, chartHeight, paused = false,
  candleOverlayToggles,
  onToggleCandleOverlay,
  customOverlayActive = false,
  onCustomOverlayActiveChange,
  onOpenCustomOverlaySettings,
  custom1OverlayActive = false,
  onCustom1OverlayActiveChange,
  onOpenCustom1OverlaySettings,
  onSplit, onRemove, onDuplicate,
  onExpand, onRestore, focusedId,
  onDragStart, onToggleHidden, onSettings,
  overlayControlsOnly = false,
  priceExtremeLabelsVisible = false,
  onTogglePriceExtremeLabels,
}) => {
  const [paneLayouts, setPaneLayouts] = useState<Array<{ paneIndex: number; topY: number; height: number }>>([]);
  const [paneItems, setPaneItems] = useState<ReturnType<typeof buildPaneItems>>([]);
  const [openMenuId, setOpenMenuId] = useState<string | null>(null);
  const [flyoutPos, setFlyoutPos] = useState({ top: 0, left: 0 });
  const indicatorsRef = useRef(indicators);
  const openTimer  = useRef<ReturnType<typeof setTimeout> | null>(null);
  const closeTimer = useRef<ReturnType<typeof setTimeout> | null>(null);

  const sync = useCallback(() => {
    setPaneLayouts(manager.getPaneLayouts());
    setPaneItems(buildPaneItems(manager, indicatorsRef.current));
  }, [manager]);

  useEffect(() => { indicatorsRef.current = indicators; }, [indicators]);

  useEffect(() => {
    if (paused) {
      setPaneItems([]);
      return;
    }
    sync();
    const unsub = manager.subscribePaneLayout(() => sync());
    return unsub;
  }, [manager, paused, sync, indicators]);

  useEffect(() => () => {
    if (openTimer.current)  clearTimeout(openTimer.current);
    if (closeTimer.current) clearTimeout(closeTimer.current);
  }, []);

  const closeFlyout = useCallback(() => {
    setOpenMenuId(null);
    if (openTimer.current)  { clearTimeout(openTimer.current);  openTimer.current  = null; }
    if (closeTimer.current) { clearTimeout(closeTimer.current); closeTimer.current = null; }
  }, []);

  const openFlyout = useCallback((itemId: string, el: HTMLElement) => {
    if (closeTimer.current) { clearTimeout(closeTimer.current); closeTimer.current = null; }
    if (openTimer.current)  clearTimeout(openTimer.current);
    openTimer.current = setTimeout(() => {
      const rect = el.getBoundingClientRect();
      setFlyoutPos({ top: rect.top, left: rect.left - 4 });
      setOpenMenuId(itemId);
    }, 80);
  }, []);

  const scheduleClose = useCallback(() => {
    if (openTimer.current) { clearTimeout(openTimer.current); openTimer.current = null; }
    closeTimer.current = setTimeout(() => setOpenMenuId(null), 200);
  }, []);

  const cancelClose = useCallback(() => {
    if (closeTimer.current) { clearTimeout(closeTimer.current); closeTimer.current = null; }
  }, []);

  const candlePane = paneLayouts.find(l => l.paneIndex === 0);
  const showOverlayIcons = !!(candleOverlayToggles?.length && candlePane && onToggleCandleOverlay);
  const showPriceExtremeBtn = !!(candlePane && onTogglePriceExtremeLabels);
  const showOverlayCluster = showOverlayIcons || showPriceExtremeBtn;

  if (paused || chartHeight <= 0) return null;
  if (overlayControlsOnly && !showOverlayCluster) return null;

  const innerHeight = paneLayouts.reduce(
    (max, l) => Math.max(max, l.topY + l.height),
    chartHeight,
  );

  const allowDrag = !!(onDragStart && paneItems.length > 1);
  const clusterHeight = (allowDrag ? BTN_SIZE + BTN_GAP : 0) + BTN_SIZE;

  const openItem = openMenuId
    ? paneItems.find(p => p.id === openMenuId)
    : null;

  const showCustomBtn = !!(showOverlayIcons && onCustomOverlayActiveChange && onOpenCustomOverlaySettings);
  const showCustom1Btn = !!(showOverlayIcons && onCustom1OverlayActiveChange && onOpenCustomOverlaySettings);
  const customMenuOpen = openMenuId === CUSTOM_MENU_ID;
  const custom1MenuOpen = openMenuId === CUSTOM1_MENU_ID;

  const focusedLayoutId = focusedId
    ? resolveFocusedPaneLayoutId(focusedId, indicators)
    : null;
  const focusedPaneLayout = focusedLayoutId
    ? (() => {
        const item = paneItems.find(p => isIndicatorPaneFocused(p.id, focusedId, indicators));
        if (item) return resolvePaneItemLayout(manager, item);
        return manager.getIndicatorPaneScreenLayout(focusedLayoutId);
      })()
    : null;

  return (
    <aside
      className={`chart-right-toolbar${overlayControlsOnly ? ' chart-right-toolbar--overlay-only' : ''}`}
      aria-label="차트 우측 도구"
    >
      <div
        className="chart-right-toolbar-inner"
        style={{ height: Math.max(innerHeight, chartHeight) }}
      >
        {focusedId && onRestore && focusedPaneLayout && (
          <div
            className="chart-right-toolbar-cluster chart-right-toolbar-cluster--focus-restore"
            style={{ top: focusedPaneLayout.topY + 4 }}
          >
            <button
              type="button"
              className="tv-side-btn chart-right-toolbar-btn chart-right-toolbar-btn--restore active"
              title="기본 보기로 복원 (모든 보조지표 표시)"
              onClick={e => { e.stopPropagation(); onRestore(); }}
            >
              <IconRestore />
            </button>
          </div>
        )}

        {showOverlayCluster && (
          <div
            className="chart-right-toolbar-cluster chart-right-toolbar-cluster--overlay-icons"
            style={{ top: candlePane!.topY + 4 }}
          >
            {candleOverlayToggles?.map((item, idx) => (
              <button
                key={item.key}
                type="button"
                className={`tv-side-btn chart-right-toolbar-btn chart-right-toolbar-btn--overlay${item.visible ? '' : ' chart-right-toolbar-btn--overlay-off'}`}
                title={item.visible ? `${item.label} 숨기기` : `${item.label} 표시`}
                style={{ marginTop: idx > 0 ? BTN_GAP : 0 }}
                onClick={e => {
                  e.stopPropagation();
                  onToggleCandleOverlay?.(item.key);
                }}
              >
                {OVERLAY_ICONS[item.key]}
              </button>
            ))}
            {showPriceExtremeBtn && (
              <button
                type="button"
                className={`tv-side-btn chart-right-toolbar-btn chart-right-toolbar-btn--overlay chart-right-toolbar-btn--price-extreme${priceExtremeLabelsVisible ? '' : ' chart-right-toolbar-btn--overlay-off'}`}
                title={priceExtremeLabelsVisible ? '9·20일 신고가·신저가 숨기기' : '9·20일 신고가·신저가 표시'}
                style={{ marginTop: (candleOverlayToggles?.length ?? 0) > 0 ? BTN_GAP : 0 }}
                onClick={e => {
                  e.stopPropagation();
                  onTogglePriceExtremeLabels?.();
                }}
              >
                <IconPriceExtreme />
              </button>
            )}
            {showCustomBtn && (
              <button
                type="button"
                className={`tv-side-btn tv-side-group-btn chart-right-toolbar-btn chart-right-toolbar-btn--custom${customOverlayActive ? ' active' : ''}${customMenuOpen ? ' active' : ''}`}
                title="Custom 표시"
                style={{ marginTop: BTN_GAP }}
                onMouseEnter={e => openFlyout(CUSTOM_MENU_ID, e.currentTarget)}
                onMouseLeave={scheduleClose}
              >
                <IconCustom />
                <span className="tv-side-expand-arrow" />
              </button>
            )}
            {showCustom1Btn && (
              <button
                type="button"
                className={`tv-side-btn tv-side-group-btn chart-right-toolbar-btn chart-right-toolbar-btn--custom1${custom1OverlayActive ? ' active' : ''}${custom1MenuOpen ? ' active' : ''}`}
                title="Custom1 표시"
                style={{ marginTop: BTN_GAP }}
                onMouseEnter={e => openFlyout(CUSTOM1_MENU_ID, e.currentTarget)}
                onMouseLeave={scheduleClose}
              >
                <IconCustom />
                <span className="chart-right-toolbar-custom1-badge">1</span>
                <span className="tv-side-expand-arrow" />
              </button>
            )}
          </div>
        )}

        {!overlayControlsOnly && paneLayouts.map(layout => (
          <div
            key={layout.paneIndex}
            className="chart-right-toolbar-segment"
            style={{ top: layout.topY, height: layout.height }}
          />
        ))}

        {!overlayControlsOnly && paneItems.map(item => {
          const pl = resolvePaneItemLayout(manager, item);
          if (!pl) return null;

          const samePaneItems = paneItems.filter(p => p.paneIndex === item.paneIndex);
          const stackIdx = samePaneItems.findIndex(p => p.id === item.id);
          const paneBottom = pl.topY + pl.height;
          const clusterTop = paneBottom - 4 - clusterHeight - stackIdx * (clusterHeight + 4);
          const menuItems = buildMenuItems(item, indicators, paneItems, {
            focusedId, onSplit, onDuplicate, onExpand, onRestore, onRemove,
            onToggleHidden, onSettings,
          });

          if (menuItems.length === 0 && !allowDrag) return null;

          return (
            <div
              key={item.id}
              className="chart-right-toolbar-cluster"
              style={{ top: clusterTop }}
            >
              {allowDrag && (
                <button
                  type="button"
                  className="tv-side-btn chart-right-toolbar-btn chart-right-toolbar-btn--drag"
                  title="드래그하여 순서 변경"
                  onPointerDown={e => {
                    e.stopPropagation();
                    onDragStart?.(item.id, e);
                  }}
                >
                  <IconDrag />
                </button>
              )}
              {menuItems.length > 0 && (
                <button
                  type="button"
                  className={`tv-side-btn tv-side-group-btn chart-right-toolbar-btn chart-right-toolbar-btn--menu${openMenuId === item.id ? ' active' : ''}`}
                  title="보조지표 메뉴"
                  onMouseEnter={e => openFlyout(item.id, e.currentTarget)}
                  onMouseLeave={scheduleClose}
                >
                  <IconMore />
                  <span className="tv-side-expand-arrow" />
                </button>
              )}
            </div>
          );
        })}
      </div>

      {customMenuOpen && showCustomBtn && (
        <CustomOverlayFlyoutMenu
          title="Custom"
          flyoutPos={flyoutPos}
          overlayActive={customOverlayActive}
          onToggleActive={() => onCustomOverlayActiveChange?.(!customOverlayActive)}
          onOpenSettings={() => onOpenCustomOverlaySettings?.()}
          onCancelClose={cancelClose}
          onScheduleClose={scheduleClose}
          onCloseFlyout={closeFlyout}
        />
      )}

      {custom1MenuOpen && showCustom1Btn && (
        <CustomOverlayFlyoutMenu
          title="Custom1"
          flyoutPos={flyoutPos}
          overlayActive={custom1OverlayActive}
          onToggleActive={() => onCustom1OverlayActiveChange?.(!custom1OverlayActive)}
          onOpenSettings={() => onOpenCustom1OverlaySettings?.()}
          onCancelClose={cancelClose}
          onScheduleClose={scheduleClose}
          onCloseFlyout={closeFlyout}
        />
      )}

      {openItem && openMenuId && openMenuId !== CUSTOM_MENU_ID && openMenuId !== CUSTOM1_MENU_ID && (() => {
        const menuItems = buildMenuItems(openItem, indicators, paneItems, {
          focusedId, onSplit, onDuplicate, onExpand, onRestore, onRemove,
          onToggleHidden, onSettings,
          onDone: closeFlyout,
        });
        if (menuItems.length === 0) return null;

        return (
          <div
            className="tv-side-flyout tv-side-flyout--right-anchor"
            style={{ top: flyoutPos.top, left: flyoutPos.left }}
            onMouseEnter={cancelClose}
            onMouseLeave={scheduleClose}
          >
            <div className="tv-side-flyout-header">{openItem.label}</div>
            {menuItems.map(mi => (
              <button
                key={mi.key}
                type="button"
                className={`tv-side-flyout-item${mi.active ? ' active' : ''}${mi.danger ? ' tv-side-flyout-item--danger' : ''}`}
                onClick={e => { e.stopPropagation(); mi.onClick(); }}
              >
                <span className="tv-side-flyout-icon">{mi.icon}</span>
                <span className="tv-side-flyout-title">{mi.title}</span>
              </button>
            ))}
          </div>
        );
      })()}
    </aside>
  );
};

export default ChartRightToolbar;
