/**
 * 캔들 pane 하단 시간축 — 거래량·보조지표가 아래에 있을 때 캔들 영역 바로 아래에도 시간 표시.
 * 크로스헤어 세로선 위치에 해당 날짜·시간 배지를 함께 표시한다.
 */
import React, { useEffect, useCallback, useRef } from 'react';
import type { MouseEventParams, Time } from 'lightweight-charts';
import type { ChartManager } from '../utils/ChartManager';
import { subscribeChartTimeFormat } from '../utils/chartTimeFormat';

const AXIS_HEIGHT = 22;

interface CandlePaneTimeAxisProps {
  manager: ChartManager;
  containerEl: HTMLElement;
}

function applyOverlayLayout(
  root: HTMLDivElement,
  pool: HTMLSpanElement[],
  state: NonNullable<ReturnType<ChartManager['getCandlePaneTimeAxisOverlay']>>,
): void {
  root.style.display = 'flex';
  root.style.top = `${state.topY}px`;
  root.style.height = `${state.height ?? AXIS_HEIGHT}px`;
  root.style.width = `${state.plotWidth}px`;

  state.labels.forEach((label, i) => {
    let span = pool[i];
    if (!span) {
      span = document.createElement('span');
      span.className = 'candle-pane-time-axis__label';
      root.appendChild(span);
      pool[i] = span;
    }
    span.style.display = '';
    span.style.left = `${label.x}px`;
    span.textContent = label.text;
  });
  for (let i = state.labels.length; i < pool.length; i++) {
    if (pool[i]) pool[i].style.display = 'none';
  }
}

const CandlePaneTimeAxis: React.FC<CandlePaneTimeAxisProps> = ({ manager, containerEl }) => {
  const axisRef = useRef<HTMLDivElement>(null);
  const crosshairRef = useRef<HTMLDivElement>(null);
  const labelPoolRef = useRef<HTMLSpanElement[]>([]);

  const updateCrosshairLabel = useCallback((p: MouseEventParams<Time>) => {
    const el = crosshairRef.current;
    if (!el) return;

    const band = manager.getCandlePaneTimeAxisBand();
    if (!band || !p.time || p.point?.x == null) {
      el.style.display = 'none';
      return;
    }

    const x = p.point.x;
    if (!Number.isFinite(x) || x < 0 || x > band.plotWidth) {
      el.style.display = 'none';
      return;
    }

    el.style.display = 'flex';
    el.style.top = `${band.topY}px`;
    el.style.height = `${band.height}px`;
    el.style.left = `${x}px`;
    el.textContent = manager.formatCrosshairAxisTime(p.time);
  }, [manager]);

  const hideCrosshairLabel = useCallback(() => {
    if (crosshairRef.current) crosshairRef.current.style.display = 'none';
  }, []);

  const renderOverlay = useCallback(() => {
    const root = axisRef.current;
    if (!root || !containerEl.isConnected) return;

    root.style.transform = '';

    const state = manager.getCandlePaneTimeAxisOverlay();
    if (!state || state.labels.length === 0) {
      root.style.display = 'none';
      for (const span of labelPoolRef.current) {
        span.style.display = 'none';
      }
      return;
    }

    applyOverlayLayout(root, labelPoolRef.current, state);
  }, [manager, containerEl]);

  useEffect(() => {
    renderOverlay();
    const ro = new ResizeObserver(renderOverlay);
    ro.observe(containerEl);

    const unsubLayout = manager.subscribePaneLayout(renderOverlay);
    const unsubRange = manager.subscribeViewport(renderOverlay);
    const unsubFormat = subscribeChartTimeFormat(renderOverlay);
    const unsubCrosshair = manager.subscribeCrosshair(updateCrosshairLabel);

    const onLeave = () => hideCrosshairLabel();
    containerEl.addEventListener('mouseleave', onLeave);

    const timers = [0, 50, 150, 400].map(ms => window.setTimeout(renderOverlay, ms));
    return () => {
      ro.disconnect();
      unsubLayout();
      unsubRange();
      unsubFormat();
      unsubCrosshair();
      containerEl.removeEventListener('mouseleave', onLeave);
      timers.forEach(clearTimeout);
    };
  }, [manager, containerEl, renderOverlay, updateCrosshairLabel, hideCrosshairLabel]);

  return (
    <>
      <div
        ref={axisRef}
        className="candle-pane-time-axis"
        style={{ display: 'none' }}
        aria-hidden
      />
      <div
        ref={crosshairRef}
        className="candle-pane-time-axis__crosshair"
        style={{ display: 'none' }}
        aria-hidden
      />
    </>
  );
};

export default CandlePaneTimeAxis;
