/**
 * 전략 평가 — 캔들 pane 세로 선택 영역 (드래그로 봉 이동)
 */
import React, { useCallback, useEffect, useRef, useState } from 'react';
import ReactDOM from 'react-dom';
import type { ChartManager } from '../../utils/ChartManager';
import type { OHLCVBar } from '../../types';
import { findNearestBarIndex } from '../../utils/analysisChartData';

interface Props {
  manager: ChartManager;
  bars: OHLCVBar[];
  selectedBarIndex: number;
  onSelectedBarIndexChange: (index: number) => void;
}

interface BarBand {
  left: number;
  width: number;
  top: number;
  height: number;
}

function resolveBarBand(
  manager: ChartManager,
  bars: OHLCVBar[],
  index: number,
): BarBand | null {
  if (index < 0 || index >= bars.length) return null;

  const main = manager.getPaneLayouts().find(l => l.paneIndex === 0);
  if (!main || main.height < 8) return null;

  const centerX = manager.timeToX(bars[index].time);
  if (centerX == null || !Number.isFinite(centerX)) return null;

  let halfWidth = 7;
  if (index > 0) {
    const prevX = manager.timeToX(bars[index - 1].time);
    if (prevX != null) halfWidth = Math.max(5, Math.abs(centerX - prevX) * 0.42);
  }
  if (index < bars.length - 1) {
    const nextX = manager.timeToX(bars[index + 1].time);
    if (nextX != null) halfWidth = Math.max(halfWidth, Math.abs(nextX - centerX) * 0.42);
  }

  const plotWidth = manager.getCandlePaneTimeAxisBand()?.plotWidth
    ?? Math.max(40, manager.getContainer().clientWidth - 64);
  const width = Math.min(Math.max(halfWidth * 2, 10), 48);
  const left = Math.max(0, Math.min(plotWidth - width, centerX - width / 2));

  return {
    left,
    width,
    top: main.topY,
    height: main.height,
  };
}

function indexFromClientX(
  manager: ChartManager,
  bars: OHLCVBar[],
  clientX: number,
): number {
  const rect = manager.getContainer().getBoundingClientRect();
  const chartX = clientX - rect.left;
  const time = manager.xToTime(chartX);
  if (time == null) return -1;
  return findNearestBarIndex(bars, time);
}

/** 차트 클릭 좌표 → 봉 index (전략선택봉 이동, 전략선택봉 영역 제외는 호출측) */
export function resolveBarIndexAtChartClick(
  manager: ChartManager,
  bars: OHLCVBar[],
  clientX: number,
  clientY: number,
): number {
  const idx = manager.resolveNearestBarIndexAtClientPoint(clientX, clientY);
  if (idx < 0 || idx >= bars.length) return -1;
  return idx;
}

const StrategyEvaluationBarSelector: React.FC<Props> = ({
  manager,
  bars,
  selectedBarIndex,
  onSelectedBarIndexChange,
}) => {
  const [band, setBand] = useState<BarBand | null>(null);
  const [dragIndex, setDragIndex] = useState<number | null>(null);
  const draggingRef = useRef(false);
  const displayIndex = dragIndex ?? selectedBarIndex;

  const refreshBand = useCallback(() => {
    setBand(resolveBarBand(manager, bars, displayIndex));
  }, [manager, bars, displayIndex]);

  useEffect(() => {
    refreshBand();
    const ro = new ResizeObserver(refreshBand);
    ro.observe(manager.getContainer());

    let raf = 0;
    const schedule = () => {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(refreshBand);
    };
    const unsubLayout = manager.subscribePaneLayout(schedule);
    const unsubViewport = manager.subscribeViewport(schedule);
    const timers = [0, 80, 200].map(ms => window.setTimeout(refreshBand, ms));

    return () => {
      ro.disconnect();
      cancelAnimationFrame(raf);
      unsubLayout();
      unsubViewport();
      timers.forEach(clearTimeout);
    };
  }, [manager, refreshBand]);

  const finishDrag = useCallback((clientX: number) => {
    draggingRef.current = false;
    setDragIndex(null);
    const idx = indexFromClientX(manager, bars, clientX);
    if (idx >= 0 && idx !== selectedBarIndex) {
      onSelectedBarIndexChange(idx);
    }
  }, [manager, bars, selectedBarIndex, onSelectedBarIndexChange]);

  const onPointerDown = useCallback((e: React.PointerEvent<HTMLDivElement>) => {
    if (e.button !== 0) return;
    e.preventDefault();
    e.stopPropagation();
    draggingRef.current = true;
    e.currentTarget.setPointerCapture(e.pointerId);

    const onMove = (ev: PointerEvent) => {
      if (!draggingRef.current) return;
      ev.preventDefault();
      ev.stopPropagation();
      const idx = indexFromClientX(manager, bars, ev.clientX);
      if (idx >= 0) setDragIndex(idx);
    };
    const onUp = (ev: PointerEvent) => {
      document.body.style.cursor = '';
      document.body.style.userSelect = '';
      finishDrag(ev.clientX);
      window.removeEventListener('pointermove', onMove);
      window.removeEventListener('pointerup', onUp);
      window.removeEventListener('pointercancel', onUp);
    };

    document.body.style.cursor = 'grabbing';
    document.body.style.userSelect = 'none';
    window.addEventListener('pointermove', onMove);
    window.addEventListener('pointerup', onUp);
    window.addEventListener('pointercancel', onUp);
  }, [manager, bars, finishDrag]);

  if (!band || bars.length === 0) return null;

  const bar = bars[displayIndex];
  const timeLabel = bar
    ? new Date(bar.time * 1000).toLocaleString('ko-KR', {
      month: 'numeric',
      day: 'numeric',
      hour: '2-digit',
      minute: '2-digit',
    })
    : '';

  return ReactDOM.createPortal(
    <div className="seval-bar-selector-layer" aria-hidden>
      <div
        data-no-chart-pan
        className={`seval-bar-selector${dragIndex != null ? ' seval-bar-selector--dragging' : ''}`}
        style={{
          left: `${band.left}px`,
          top: `${band.top}px`,
          width: `${band.width}px`,
          height: `${band.height}px`,
        }}
        onPointerDown={onPointerDown}
        title="드래그하여 분석 봉 이동"
      >
        <div className="seval-bar-selector__shine" />
        <div className="seval-bar-selector__handle" />
        {timeLabel && (
          <div className="seval-bar-selector__label">{timeLabel}</div>
        )}
      </div>
    </div>,
    manager.getContainer(),
  );
};

export default StrategyEvaluationBarSelector;
