import { useMemo, useRef, useState } from 'react';
import {
  WEATHER_LAYERS,
  LEGEND_META,
  SPEED_OPTIONS,
  type WeatherLayerId,
  type WeatherOverlayState,
  type WeatherOverlayActions,
} from '../../features/weatherOverlay/useWeatherOverlay';

type Props = WeatherOverlayState & WeatherOverlayActions;

/** 절대 시간 표기 (MM. DD. HH:mm) */
function fmtBase(d: Date | null): string {
  if (!d) return '-';
  const mm = String(d.getMonth() + 1).padStart(2, '0');
  const dd = String(d.getDate()).padStart(2, '0');
  const hh = String(d.getHours()).padStart(2, '0');
  const mi = String(d.getMinutes()).padStart(2, '0');
  return `${mm}. ${dd}. ${hh}:${mi}`;
}

/** epoch 초 → Date */
function secToDate(sec: number): Date {
  return new Date(sec * 1000);
}

/** 기준시간 대비 오프셋 표기 (+HH:MM) */
function fmtOffset(base: Date | null, target: Date | null): string {
  if (!base || !target) return '-';
  const diffMs = target.getTime() - base.getTime();
  const totalMin = Math.round(diffMs / 60_000);
  const h = Math.floor(Math.abs(totalMin) / 60);
  const m = Math.abs(totalMin) % 60;
  const sign = totalMin >= 0 ? '+' : '-';
  return `${sign}${h}:${String(m).padStart(2, '0')}`;
}

/** ColorRamp → CSS linear-gradient */
function rampToGradient(layerId: WeatherLayerId): string {
  const { colorRamp } = LEGEND_META[layerId];
  const stops = colorRamp.getRawColorStops();
  if (stops.length === 0) return 'transparent';
  const { min, max } = colorRamp.getBounds();
  const range = max - min || 1;
  const css = stops.map((s) => {
    const [r, g, b, a] = s.color;
    const pct = ((s.value - min) / range) * 100;
    return `rgba(${r},${g},${b},${(a ?? 255) / 255}) ${pct.toFixed(1)}%`;
  });
  return `linear-gradient(to right, ${css.join(', ')})`;
}

/** 범례 눈금 생성 */
function getLegendTicks(layerId: WeatherLayerId): string[] {
  const { colorRamp, unit } = LEGEND_META[layerId];
  const { min, max } = colorRamp.getBounds();
  const count = 5;
  const step = (max - min) / count;
  const ticks: string[] = [];
  for (let i = 0; i <= count; i++) {
    const v = min + step * i;
    ticks.push(Number.isInteger(v) ? String(v) : v.toFixed(1));
  }
  ticks[ticks.length - 1] += unit;
  return ticks;
}

/** steps 배열에서 value 에 가장 가까운 step epoch 초 반환 */
function snapToStep(steps: number[], value: number): number {
  if (steps.length === 0) return value;
  let best = steps[0];
  let bestDist = Math.abs(value - best);
  for (let i = 1; i < steps.length; i++) {
    const dist = Math.abs(value - steps[i]);
    if (dist < bestDist) {
      best = steps[i];
      bestDist = dist;
    }
  }
  return best;
}

export function WeatherOverlayPanel(props: Props) {
  const {
    enabled,
    activeLayerId,
    opacity,
    isPlaying,
    animationSpeed,
    currentTime,
    startTime,
    endTime,
    steps,
    isReady,
    toggleLayer,
    setOpacity,
    play,
    pause,
    setSpeed,
    seekTo,
  } = props;

  const [open, setOpen] = useState(false);
  const activeCount = Object.values(enabled).filter(Boolean).length;
  /** 드래그 중 현재 step index */
  const [draggingIdx, setDraggingIdx] = useState<number | null>(null);
  /** 마지막으로 seek 요청한 step index (중복 방지) */
  const lastSeekedRef = useRef<number | null>(null);

  const legendGradient = useMemo(
    () => (activeLayerId ? rampToGradient(activeLayerId) : null),
    [activeLayerId],
  );
  const legendTicks = useMemo(
    () => (activeLayerId ? getLegendTicks(activeLayerId) : []),
    [activeLayerId],
  );

  // 현재 시간을 step index로 변환 (재생 중 폴링 값 반영)
  const currentStepIdx =
    draggingIdx != null
      ? draggingIdx
      : steps.length > 0 && currentTime
        ? (() => {
            const curSec = currentTime.getTime() / 1000;
            const snapped = snapToStep(steps, curSec);
            return steps.indexOf(snapped);
          })()
        : 0;

  /** 드래그 중: step 경계를 넘을 때마다 실시간 seek */
  const handleSliderInput = (e: React.ChangeEvent<HTMLInputElement>) => {
    const idx = Number(e.target.value);
    setDraggingIdx(idx);
    // step이 바뀌었을 때만 seek (동일 step 반복 방지)
    if (lastSeekedRef.current !== idx && steps[idx] != null) {
      lastSeekedRef.current = idx;
      seekTo(steps[idx]);
    }
  };

  /** 드래그 끝: 정리 */
  const handleSliderCommit = () => {
    lastSeekedRef.current = null;
    setDraggingIdx(null);
  };

  const legendInfo = activeLayerId ? LEGEND_META[activeLayerId] : null;
  const showPanel = open;
  const showLegend = !!activeLayerId && !!legendInfo && !!legendGradient;

  return (
    <>
      <button
        className={`wo-gear${open ? ' open' : ''}${activeCount > 0 ? ' active' : ''}`}
        onClick={() => {
          setOpen((prev) => {
            if (prev && activeCount > 0) {
              toggleLayer(activeLayerId!);
              pause();
            }
            return !prev;
          });
        }}
        title="기상 타일 오버레이"
        type="button"
      >
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
          <path d="M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" />
          <circle cx="12" cy="12" r="3" />
        </svg>
        {activeCount > 0 && <span className="wo-gear-badge">{activeCount}</span>}
      </button>

      {(showPanel || showLegend) && (
        <div className="wo-stack">
          {showPanel && (
            <div className="wo-panel">
              <div className="wo-header">
                <span className="wo-title">기상 타일 오버레이</span>
                {!isReady && activeCount > 0 && <span className="wo-loading">로딩...</span>}
              </div>

              <div className="wo-layers">
                {WEATHER_LAYERS.map((meta) => (
                  <button
                    key={meta.id}
                    className={`wo-layer-btn${enabled[meta.id] ? ' on' : ''}`}
                    onClick={() => toggleLayer(meta.id as WeatherLayerId)}
                    title={meta.label}
                    type="button"
                  >
                    <span className="wo-layer-icon">{meta.icon}</span>
                    <span className="wo-layer-name">{meta.label}</span>
                  </button>
                ))}
              </div>

              <div className="wo-section">
                <div className="wo-label">
                  투명도 <span className="wo-val">{Math.round(opacity * 100)}%</span>
                </div>
                <input
                  type="range"
                  className="wo-slider"
                  min={0}
                  max={100}
                  value={Math.round(opacity * 100)}
                  onChange={(e) => setOpacity(Number(e.target.value) / 100)}
                />
              </div>

              {activeCount > 0 && steps.length > 0 && (
                <div className="wo-section wo-timeline">
                  <div className="wo-label">
                    기준 <span className="wo-val">{fmtBase(startTime)}</span>
                    {' · '}
                    <span className="wo-val wo-offset">{fmtOffset(startTime, currentTime)}</span>
                  </div>

                  {/* step 기반 슬라이더 */}
                  <div className="wo-step-slider-wrap">
                    <input
                      type="range"
                      className="wo-slider wo-time-slider"
                      min={0}
                      max={steps.length - 1}
                      step={1}
                      value={currentStepIdx}
                      onChange={handleSliderInput}
                      onMouseUp={handleSliderCommit}
                      onTouchEnd={handleSliderCommit}
                      disabled={!isReady}
                    />
                    {/* 눈금 표시 */}
                    <div className="wo-step-ticks">
                      {steps.map((sec, i) => {
                        const pct = steps.length > 1 ? (i / (steps.length - 1)) * 100 : 0;
                        const d = secToDate(sec);
                        const isDay = d.getHours() === 0 && d.getMinutes() === 0;
                        return (
                          <span
                            key={sec}
                            className={`wo-step-tick${isDay ? ' day' : ''}`}
                            style={{ left: `${pct}%` }}
                          />
                        );
                      })}
                    </div>
                  </div>

                  <div className="wo-time-range">
                    <span>{fmtBase(startTime)}</span>
                    <span>
                      {draggingIdx != null && steps[draggingIdx]
                        ? fmtBase(secToDate(steps[draggingIdx]))
                        : fmtBase(currentTime)}
                    </span>
                    <span>{fmtBase(endTime)}</span>
                  </div>

                  <div className="wo-playback">
                    <button
                      className="wo-play-btn"
                      type="button"
                      onClick={isPlaying ? pause : play}
                      disabled={!isReady}
                      title={isPlaying ? '일시정지' : '재생'}
                    >
                      {isPlaying ? '⏸' : '▶'}
                    </button>
                    <div className="wo-speed-btns">
                      {SPEED_OPTIONS.map((opt) => (
                        <button
                          key={opt.value}
                          className={`wo-speed-btn${animationSpeed === opt.value ? ' on' : ''}`}
                          onClick={() => setSpeed(opt.value)}
                          type="button"
                          title={`${opt.label} 속도`}
                        >
                          {opt.label}
                        </button>
                      ))}
                    </div>
                  </div>
                </div>
              )}

              <div className="wo-hint">
                MapTiler Weather SDK
              </div>
            </div>
          )}

          {showLegend && (
            <div className="wo-legend">
              <div className="wo-legend-header">
                {legendInfo!.label} ({legendInfo!.unit})
              </div>
              <div
                className="wo-legend-bar"
                style={{ background: legendGradient! }}
              />
              <div className="wo-legend-ticks">
                {legendTicks.map((t, i) => (
                  <span key={i}>{t}</span>
                ))}
              </div>
            </div>
          )}
        </div>
      )}
    </>
  );
}
