import { useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { ClockCounterClockwiseIcon, XIcon } from '@phosphor-icons/react'

/**
 * Time-travel picker с visual timeline.
 *
 * <p>Horizontal SVG-track с tick marks на каждой уникальной дате изменения
 * (validFrom активных версий records этого справочника). Draggable cursor
 * показывает текущий {@code at}. Click on track → jump.
 *
 * <p>Range: от min(marks) (или −1y если меток нет) до now + small padding.
 * Year/month labels на оси автомасштабируются по диапазону.
 *
 * <p>Quick-preset chips для быстрых прыжков (Сейчас / −1ч / Вчера / −7д / −30д
 * / −1г). Status footer показывает absolute date + relative-time через
 * {@code Intl.RelativeTimeFormat}.
 */
export function TimeTravelPicker({
  value,
  onChange,
  onClear,
  onClose,
  /** Уникальные validFrom timestamps (ms epoch) — рендерятся как tick marks. */
  marks = [],
}: {
  value: string | undefined
  onChange: (iso: string) => void
  onClear: () => void
  onClose: () => void
  marks?: number[]
}) {
  const { t, i18n } = useTranslation()
  const lang = (i18n.language || 'ru').split('-')[0]

  const valueDate = useMemo(() => {
    if (!value) return undefined
    const d = new Date(value)
    return Number.isNaN(d.getTime()) ? undefined : d
  }, [value])

  // Range: from min(marks, value) − padding до now + padding.
  const range = useMemo(() => {
    const now = Date.now()
    let minMark = marks.length > 0 ? Math.min(...marks) : now - 365 * 86_400_000
    if (valueDate) minMark = Math.min(minMark, valueDate.getTime())
    const span = now - minMark
    const pad = Math.max(span * 0.05, 86_400_000) // ≥1 день
    return { min: minMark - pad, max: now + pad }
  }, [marks, valueDate])

  return (
    <div className="flex flex-col gap-3 px-4 py-3 rounded-md border border-warn bg-warn-bg text-body">
      <div className="flex items-center gap-2">
        <ClockCounterClockwiseIcon weight="bold" size={16} className="text-warn" />
        <span className="text-cap font-display text-ink-2">
          {t('timeTravel.label')}
        </span>
        <button
          type="button"
          className="ml-auto text-cell text-mute hover:text-ink hover:underline inline-flex items-center gap-1"
          onClick={onClose}
        >
          <XIcon weight="bold" size={12} />
          {t('timeTravel.close')}
        </button>
      </div>

      <TimelineTrack
        range={range}
        marks={marks}
        value={valueDate}
        onChange={(d) => onChange(d.toISOString())}
        lang={lang}
      />

      <QuickPresets onPick={(deltaMs) => onChange(new Date(Date.now() + deltaMs).toISOString())} />

      <StatusFooter
        valueDate={valueDate}
        lang={lang}
        onClear={onClear}
        onChangeTime={(hours, minutes) => {
          const base = valueDate ?? new Date()
          const d = new Date(
            base.getFullYear(),
            base.getMonth(),
            base.getDate(),
            hours,
            minutes,
            0,
            0,
          )
          onChange(d.toISOString())
        }}
      />
    </div>
  )
}

// ===== Timeline track =====================================================

const TRACK_HEIGHT = 56
const TRACK_PAD_X = 12

function TimelineTrack({
  range,
  marks,
  value,
  onChange,
  lang,
}: {
  range: { min: number; max: number }
  marks: number[]
  value: Date | undefined
  onChange: (d: Date) => void
  lang: string
}) {
  const wrapperRef = useRef<HTMLDivElement>(null)
  const [width, setWidth] = useState(800)
  const [dragging, setDragging] = useState(false)
  const [hover, setHover] = useState<number | null>(null)

  // Resize observer для responsive ширины track'а.
  useEffect(() => {
    const el = wrapperRef.current
    if (!el) return
    const ro = new ResizeObserver(() => {
      setWidth(el.clientWidth)
    })
    ro.observe(el)
    setWidth(el.clientWidth)
    return () => ro.disconnect()
  }, [])

  const innerW = Math.max(width - TRACK_PAD_X * 2, 100)
  const span = range.max - range.min || 1

  const timeToX = (t: number) => TRACK_PAD_X + ((t - range.min) / span) * innerW
  const xToTime = (x: number) => {
    const clamped = Math.max(TRACK_PAD_X, Math.min(width - TRACK_PAD_X, x))
    return range.min + ((clamped - TRACK_PAD_X) / innerW) * span
  }

  const handlePointerDown = (e: React.PointerEvent<SVGSVGElement>) => {
    ;(e.target as Element).setPointerCapture?.(e.pointerId)
    setDragging(true)
    const rect = e.currentTarget.getBoundingClientRect()
    onChange(new Date(xToTime(e.clientX - rect.left)))
  }
  const handlePointerMove = (e: React.PointerEvent<SVGSVGElement>) => {
    const rect = e.currentTarget.getBoundingClientRect()
    const t = xToTime(e.clientX - rect.left)
    setHover(t)
    if (dragging) onChange(new Date(t))
  }
  const handlePointerUp = (e: React.PointerEvent<SVGSVGElement>) => {
    ;(e.target as Element).releasePointerCapture?.(e.pointerId)
    setDragging(false)
  }
  const handlePointerLeave = () => {
    setHover(null)
  }

  // Year/month tick labels — выбираем интервал в зависимости от span.
  const yearTicks = useMemo(() => buildAxisTicks(range.min, range.max), [range.min, range.max])

  const cursorX = value ? timeToX(value.getTime()) : timeToX(Date.now())
  const hasValue = Boolean(value)
  const nowX = timeToX(Date.now())

  // Tooltip для hover над треком (ещё не drop'нул) — без перетаскивания.
  const tooltipText = useMemo(() => {
    if (hover === null) return null
    return new Date(hover).toLocaleString(lang === 'en' ? 'en-US' : 'ru-RU', {
      dateStyle: 'medium',
      timeStyle: 'short',
    })
  }, [hover, lang])

  return (
    <div ref={wrapperRef} className="relative w-full select-none">
      <svg
        width={width}
        height={TRACK_HEIGHT}
        viewBox={`0 0 ${width} ${TRACK_HEIGHT}`}
        className="block touch-none cursor-pointer"
        onPointerDown={handlePointerDown}
        onPointerMove={handlePointerMove}
        onPointerUp={handlePointerUp}
        onPointerCancel={handlePointerUp}
        onPointerLeave={handlePointerLeave}
      >
        {/* Track baseline */}
        <line
          x1={TRACK_PAD_X}
          x2={width - TRACK_PAD_X}
          y1={TRACK_HEIGHT / 2}
          y2={TRACK_HEIGHT / 2}
          stroke="#d4d4d8"
          strokeWidth={2}
          strokeLinecap="round"
        />

        {/* Past portion highlighted (от min до cursor) */}
        {hasValue && (
          <line
            x1={TRACK_PAD_X}
            x2={cursorX}
            y1={TRACK_HEIGHT / 2}
            y2={TRACK_HEIGHT / 2}
            stroke="#3b82f6"
            strokeWidth={3}
            strokeLinecap="round"
            opacity={0.5}
          />
        )}

        {/* Now indicator (right edge) */}
        <g>
          <line
            x1={nowX}
            x2={nowX}
            y1={TRACK_HEIGHT / 2 - 8}
            y2={TRACK_HEIGHT / 2 + 8}
            stroke="#16a34a"
            strokeWidth={2}
            strokeLinecap="round"
          />
          <text
            x={nowX}
            y={TRACK_HEIGHT / 2 - 12}
            textAnchor="middle"
            fontSize={9}
            fontFamily="ui-monospace,monospace"
            fill="#16a34a"
          >
            now
          </text>
        </g>

        {/* Year axis ticks (выше baseline) */}
        {yearTicks.map((tick) => {
          const x = timeToX(tick.t)
          return (
            <g key={tick.t}>
              <line
                x1={x}
                x2={x}
                y1={TRACK_HEIGHT / 2 + 4}
                y2={TRACK_HEIGHT / 2 + 8}
                stroke="#a1a1aa"
                strokeWidth={1}
              />
              <text
                x={x}
                y={TRACK_HEIGHT - 4}
                textAnchor="middle"
                fontSize={9}
                fontFamily="ui-monospace,monospace"
                fill="#71717a"
              >
                {tick.label}
              </text>
            </g>
          )
        })}

        {/* Record marks (validFrom timestamps) — vertical ticks above track */}
        {marks.map((m) => {
          const x = timeToX(m)
          return (
            <line
              key={m}
              x1={x}
              x2={x}
              y1={TRACK_HEIGHT / 2 - 10}
              y2={TRACK_HEIGHT / 2 - 2}
              stroke="#7c3aed"
              strokeWidth={1.5}
              strokeLinecap="round"
              opacity={0.8}
            />
          )
        })}

        {/* Cursor (draggable) */}
        <g>
          <circle
            cx={cursorX}
            cy={TRACK_HEIGHT / 2}
            r={9}
            fill={hasValue ? '#3b82f6' : '#94a3b8'}
            stroke="#fff"
            strokeWidth={2}
            style={{ cursor: dragging ? 'grabbing' : 'grab' }}
          />
          <circle
            cx={cursorX}
            cy={TRACK_HEIGHT / 2}
            r={3}
            fill="#fff"
          />
        </g>
      </svg>

      {tooltipText && hover !== null && (
        <div
          className="text-mono absolute -top-2 -translate-y-full px-2 py-0.5 rounded bg-ink text-white pointer-events-none whitespace-nowrap"
          style={{ left: timeToX(hover), transform: 'translate(-50%, -100%)' }}
        >
          {tooltipText}
        </div>
      )}

      {marks.length > 0 && (
        <div className="text-cell text-mute font-display mt-1">
          {marks.length === 1
            ? '1 точка изменений'
            : marks.length < 5
              ? `${marks.length} точки изменений`
              : `${marks.length} точек изменений`}
        </div>
      )}
    </div>
  )
}

// ===== Quick preset chips =================================================

function QuickPresets({ onPick }: { onPick: (deltaMs: number) => void }) {
  const { t } = useTranslation()
  const presets: ReadonlyArray<{ key: string; label: string; deltaMs: number }> = [
    { key: 'now', label: t('timeTravel.preset.now'), deltaMs: 0 },
    { key: '-1h', label: t('timeTravel.preset.hourAgo'), deltaMs: -3_600_000 },
    { key: '-1d', label: t('timeTravel.preset.dayAgo'), deltaMs: -86_400_000 },
    { key: '-7d', label: t('timeTravel.preset.weekAgo'), deltaMs: -7 * 86_400_000 },
    { key: '-30d', label: t('timeTravel.preset.monthAgo'), deltaMs: -30 * 86_400_000 },
    { key: '-1y', label: t('timeTravel.preset.yearAgo'), deltaMs: -365 * 86_400_000 },
  ]
  return (
    <div className="flex flex-wrap items-center gap-1.5">
      <span className="text-cap text-mute font-display mr-1">
        {t('timeTravel.quickPresets')}
      </span>
      {presets.map((p) => (
        <button
          key={p.key}
          type="button"
          onClick={() => onPick(p.deltaMs)}
 className="text-cap px-2.5 py-1 rounded-full border border-line hover:border-accent hover:bg-accent/4 text-ink transition-colors"
        >
          {p.label}
        </button>
      ))}
    </div>
  )
}

// ===== Status footer + time tweaker =======================================

function StatusFooter({
  valueDate,
  lang,
  onClear,
  onChangeTime,
}: {
  valueDate: Date | undefined
  lang: string
  onClear: () => void
  onChangeTime: (hours: number, minutes: number) => void
}) {
  const { t } = useTranslation()

  const relativeLabel = useMemo(() => {
    if (!valueDate) return null
    const rtf = new Intl.RelativeTimeFormat(lang, { numeric: 'auto' })
    const diffMs = valueDate.getTime() - Date.now()
    const absH = Math.abs(diffMs) / 3_600_000
    const absD = absH / 24
    if (absH < 1) return rtf.format(Math.round(diffMs / 60_000), 'minute')
    if (absH < 48) return rtf.format(Math.round(diffMs / 3_600_000), 'hour')
    if (absD < 60) return rtf.format(Math.round(diffMs / 86_400_000), 'day')
    return rtf.format(Math.round(diffMs / (86_400_000 * 30)), 'month')
  }, [valueDate, lang])

  if (!valueDate) {
    return (
      <div className="text-cell text-mute font-display italic">
        {t('timeTravel.hint')}
      </div>
    )
  }

  return (
    <div className="flex flex-wrap items-center gap-2 pt-2 border-t border-warn/30">
      <ClockCounterClockwiseIcon weight="regular" size={14} className="text-warn shrink-0" />
      <span className="text-mono text-ink">
        {valueDate.toLocaleString(lang === 'en' ? 'en-US' : 'ru-RU', {
          dateStyle: 'long',
          timeStyle: 'short',
        })}
      </span>
      {relativeLabel && (
        <span className="text-cell text-mute font-display lowercase">
          ({relativeLabel})
        </span>
      )}
      <span className="ml-2 inline-flex items-center gap-1">
        <input
          type="number"
          min={0}
          max={23}
          value={String(valueDate.getHours()).padStart(2, '0')}
          onChange={(e) =>
            onChangeTime(
              Math.max(0, Math.min(23, parseInt(e.target.value, 10) || 0)),
              valueDate.getMinutes(),
            )
          }
          className="text-mono w-10 px-1.5 py-0.5 rounded-sm border border-line bg-surface text-center"
          aria-label={t('timeTravel.hours')}
        />
        <span className="text-mono text-mute">:</span>
        <input
          type="number"
          min={0}
          max={59}
          value={String(valueDate.getMinutes()).padStart(2, '0')}
          onChange={(e) =>
            onChangeTime(
              valueDate.getHours(),
              Math.max(0, Math.min(59, parseInt(e.target.value, 10) || 0)),
            )
          }
          className="text-mono w-10 px-1.5 py-0.5 rounded-sm border border-line bg-surface text-center"
          aria-label={t('timeTravel.minutes')}
        />
      </span>
      <button
        type="button"
        className="ml-auto text-cell text-accent hover:underline"
        onClick={onClear}
      >
        {t('timeTravel.clear')}
      </button>
    </div>
  )
}

// ===== Axis tick computation ==============================================

/**
 * Auto-pick tick density по диапазону:
 * - >5 лет → tick на каждый год
 * - 1-5 лет → tick на каждый квартал
 * - 1-12 месяцев → tick на каждый месяц
 * - <1 месяца → tick на неделю/несколько дней
 */
function buildAxisTicks(min: number, max: number): { t: number; label: string }[] {
  const span = max - min
  const yearMs = 365 * 86_400_000
  const out: { t: number; label: string }[] = []

  if (span > 5 * yearMs) {
    // Yearly
    const start = new Date(min)
    start.setMonth(0, 1)
    start.setHours(0, 0, 0, 0)
    let y = start.getFullYear()
    while (true) {
      const t = new Date(y, 0, 1).getTime()
      if (t > max) break
      if (t >= min) out.push({ t, label: String(y) })
      y++
    }
  } else if (span > yearMs) {
    // Quarterly
    const start = new Date(min)
    start.setDate(1)
    start.setHours(0, 0, 0, 0)
    let y = start.getFullYear()
    let m = Math.floor(start.getMonth() / 3) * 3
    while (true) {
      const d = new Date(y, m, 1)
      if (d.getTime() > max) break
      if (d.getTime() >= min) {
        out.push({ t: d.getTime(), label: `${quarterLabel(m)} ${String(y).slice(2)}` })
      }
      m += 3
      if (m >= 12) {
        m = 0
        y++
      }
    }
  } else if (span > 30 * 86_400_000) {
    // Monthly
    const start = new Date(min)
    start.setDate(1)
    start.setHours(0, 0, 0, 0)
    let y = start.getFullYear()
    let m = start.getMonth()
    while (true) {
      const d = new Date(y, m, 1)
      if (d.getTime() > max) break
      if (d.getTime() >= min) {
        out.push({ t: d.getTime(), label: monthShort(m) })
      }
      m++
      if (m >= 12) {
        m = 0
        y++
      }
    }
  } else {
    // Weekly (~7d)
    const dayMs = 86_400_000
    const start = new Date(min)
    start.setHours(0, 0, 0, 0)
    let t = start.getTime()
    while (t <= max) {
      if (t >= min) {
        const d = new Date(t)
        out.push({ t, label: `${d.getDate()} ${monthShort(d.getMonth())}` })
      }
      t += 7 * dayMs
    }
  }
  // Limit overcrowding
  if (out.length > 14) {
    const stride = Math.ceil(out.length / 12)
    return out.filter((_, i) => i % stride === 0)
  }
  return out
}

function quarterLabel(month: number): string {
  return `Q${Math.floor(month / 3) + 1}`
}
function monthShort(m: number): string {
  return ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'][m] ?? ''
}
