import React, { useEffect, useMemo, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { X, Moon, Sunrise } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { usePlayerStore } from '@/features/playback/store/playerStore';
import { useAuthStore } from '@/store/authStore';
import { useShallow } from 'zustand/react/shallow';

import type { TFunction } from 'i18next';
import { formatPlaybackScheduleRemaining } from '@/features/playback/utils/playbackScheduleFormat';
import { formatClockTime } from '@/lib/format/formatClockTime';
import {
  isValidPlaybackSchedulePreviewTimestamp,
  parsePlaybackDelayCustomMinutes,
  scheduleDelayMsFromSeconds,
  scheduleSecondsFromCustomMinutes,
} from '@/features/playback/utils/playback/playbackScheduleDelay';

/** One tap = schedule; custom minutes still covers any duration. */
const PRESET_SECONDS = [30, 60, 120, 300, 600, 900, 1800, 3600] as const;

function formatPresetLabel(seconds: number, t: TFunction): string {
  if (seconds < 60) return t('player.delayFmtSec', { n: seconds });
  if (seconds < 3600) return t('player.delayFmtMin', { n: seconds / 60 });
  return t('player.delayFmtHr', { n: seconds / 3600 });
}

function computeAnchoredPanelStyle(anchorEl: HTMLElement): React.CSSProperties {
  const ar = anchorEl.getBoundingClientRect();
  const mw = Math.min(360, Math.max(200, window.innerWidth - 32));
  let left = ar.left + ar.width / 2 - mw / 2;
  const pad = 12;
  left = Math.max(pad, Math.min(left, window.innerWidth - mw - pad));
  const gap = 10;
  return {
    position: 'fixed',
    left,
    bottom: window.innerHeight - ar.top + gap,
    width: mw,
    maxWidth: 360,
    margin: 0,
    maxHeight: 'min(72vh, calc(100vh - 24px))',
    overflowY: 'auto',
  };
}

export interface PlaybackDelayModalProps {
  open: boolean;
  onClose: () => void;
  /** When set, panel is fixed just above this element (transport strip). */
  anchorRef?: React.RefObject<HTMLElement | null>;
}

export default function PlaybackDelayModal({ open, onClose, anchorRef }: PlaybackDelayModalProps) {
  const { t, i18n } = useTranslation();
  const {
    isPlaying,
    currentTrack,
    currentRadio,
    scheduledPauseAtMs,
    scheduledResumeAtMs,
    schedulePauseIn,
    scheduleResumeIn,
    clearScheduledPause,
    clearScheduledResume,
  } = usePlayerStore(
    useShallow(s => ({
      isPlaying: s.isPlaying,
      currentTrack: s.currentTrack,
      currentRadio: s.currentRadio,
      scheduledPauseAtMs: s.scheduledPauseAtMs,
      scheduledResumeAtMs: s.scheduledResumeAtMs,
      schedulePauseIn: s.schedulePauseIn,
      scheduleResumeIn: s.scheduleResumeIn,
      clearScheduledPause: s.clearScheduledPause,
      clearScheduledResume: s.clearScheduledResume,
    })),
  );

  const [nowTick, setNowTick] = useState(() => Date.now());
  const [posTick, setPosTick] = useState(0);
  const [customMinutes, setCustomMinutes] = useState('');
  /** Preset-seconds the user is currently hovering — drives the live "Pauses at HH:MM" preview. */
  const [hoverSeconds, setHoverSeconds] = useState<number | null>(null);
  const customInputRef = useRef<HTMLInputElement | null>(null);

  useEffect(() => {
    if (!open) return;
    // React Compiler set-state-in-effect rule: state set from a timer/animation callback.
    // eslint-disable-next-line react-hooks/set-state-in-effect
    setCustomMinutes('');
    setHoverSeconds(null);
  }, [open]);

  // While modal is open, refresh the "now" tick every second so the live
  // preview clock stays accurate.
  useEffect(() => {
    if (!open) return;
    const id = window.setInterval(() => setNowTick(Date.now()), 1000);
    return () => window.clearInterval(id);
  }, [open]);

  useEffect(() => {
    if (!open) return;
    if (scheduledPauseAtMs == null && scheduledResumeAtMs == null) return;
    const id = window.setInterval(() => setNowTick(Date.now()), 500);
    return () => window.clearInterval(id);
  }, [open, scheduledPauseAtMs, scheduledResumeAtMs]);

  useEffect(() => {
    if (!open || !anchorRef) return;
    const bump = () => setPosTick(x => x + 1);
    window.addEventListener('resize', bump);
    window.addEventListener('scroll', bump, true);
    return () => {
      window.removeEventListener('resize', bump);
      window.removeEventListener('scroll', bump, true);
    };
  }, [open, anchorRef]);

  useEffect(() => {
    if (!open) return;
    const onKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape') onClose();
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [open, onClose]);

  const canPauseLater = isPlaying && (!!currentTrack || !!currentRadio);
  const canStartLater = !isPlaying && (!!currentTrack || !!currentRadio);

  const customSeconds = useMemo(() => {
    const minutes = parsePlaybackDelayCustomMinutes(customMinutes);
    if (minutes == null) return null;
    return scheduleSecondsFromCustomMinutes(minutes);
  }, [customMinutes]);

  const applyPause = (sec: number) => {
    schedulePauseIn(sec);
    onClose();
  };

  const applyStart = (sec: number) => {
    scheduleResumeIn(sec);
    onClose();
  };

  const useAnchor = !!anchorRef;
  // React Compiler refs rule: ref read imperatively outside reactive rendering; not used to compute the render output.
  // eslint-disable-next-line react-hooks/refs
  const anchorEl = anchorRef?.current ?? null;
  void posTick;
  const anchoredPanelStyle =
    open && useAnchor && anchorEl ? computeAnchoredPanelStyle(anchorEl) : undefined;

  const heading =
    canPauseLater ? t('player.delayPauseSection') : canStartLater ? t('player.delayStartSection') : t('player.delayModalTitle');

  // Mode determines icon + colour accent ("mood") of the modal.
  const mode: 'pause' | 'start' | 'idle' =
    canPauseLater ? 'pause' : canStartLater ? 'start' : 'idle';
  const HeadingIcon = mode === 'pause' ? Moon : mode === 'start' ? Sunrise : null;

  // Live preview: seconds that would be applied right now if the user clicked.
  // Priority: hovered chip → typed custom minutes → nothing.
  const clockFormat = useAuthStore(s => s.clockFormat);
  const previewSeconds = hoverSeconds ?? customSeconds;
  const previewAtMs =
    previewSeconds != null
      ? nowTick + scheduleDelayMsFromSeconds(previewSeconds)
      : null;
  const previewClock =
    previewAtMs != null && isValidPlaybackSchedulePreviewTimestamp(previewAtMs)
      ? formatClockTime(previewAtMs, clockFormat, i18n.language)
      : null;

  if (!open) return null;

  const defaultPanelStyle: React.CSSProperties = { maxWidth: 360, width: 'min(360px, calc(100vw - 32px))' };
  const panelStyle = anchoredPanelStyle ? { ...defaultPanelStyle, ...anchoredPanelStyle } : defaultPanelStyle;

  const scheduledAt = canPauseLater ? scheduledPauseAtMs : canStartLater ? scheduledResumeAtMs : null;
  const clearScheduled = canPauseLater ? clearScheduledPause : canStartLater ? clearScheduledResume : null;
  const cancelLabel = canPauseLater ? t('player.delayCancelPause') : t('player.delayCancelStart');
  const apply = canPauseLater ? applyPause : applyStart;

  return createPortal(
    <div
      className={`modal-overlay playback-delay-modal-overlay${useAnchor ? ' playback-delay-modal-overlay--anchored' : ''}`}
      onClick={onClose}
      role="dialog"
      aria-modal="true"
      aria-labelledby="playback-delay-modal-title"
      style={
        useAnchor
          ? { alignItems: 'stretch', justifyContent: 'flex-start', padding: 0 }
          : { alignItems: 'center', paddingTop: 0 }
      }
    >
      <div
        className={`modal-content playback-delay-modal playback-delay-modal--${mode}`}
        data-pd-mode={mode}
        onClick={e => e.stopPropagation()}
        style={panelStyle}
      >
        <button type="button" className="modal-close" onClick={onClose} aria-label={t('player.closeDelayModal')}>
          <X size={18} />
        </button>

        <div className="playback-delay-modal__head">
          {HeadingIcon && (
            <span className="playback-delay-modal__icon" aria-hidden="true">
              <HeadingIcon size={18} />
            </span>
          )}
          <h3 id="playback-delay-modal-title" className="playback-delay-modal__title">
            {heading}
          </h3>
        </div>

        {(canPauseLater || canStartLater) && (
          <>
            {scheduledAt != null && (
              <div className="playback-delay-section__head playback-delay-section__head--tight">
                <span className="playback-delay-section__countdown">
                  {t('player.delayIn')} {formatPlaybackScheduleRemaining(scheduledAt, nowTick)}
                </span>
                {clearScheduled && (
                  <button
                    type="button"
                    className="btn btn-ghost btn-sm playback-delay-inline-cancel"
                    aria-label={cancelLabel}
                    onClick={() => clearScheduled()}
                  >
                    {t('player.delayCancel')}
                  </button>
                )}
              </div>
            )}
            <div
              className="playback-delay-chips playback-delay-chips--compact"
              onMouseLeave={() => setHoverSeconds(null)}
            >
              {PRESET_SECONDS.map(sec => (
                <button
                  key={`pr-${sec}`}
                  type="button"
                  className="playback-delay-chip"
                  onMouseEnter={() => setHoverSeconds(sec)}
                  onFocus={() => setHoverSeconds(sec)}
                  onBlur={() => setHoverSeconds(null)}
                  onClick={() => apply(sec)}
                >
                  {formatPresetLabel(sec, t)}
                </button>
              ))}
            </div>

            <div className="playback-delay-custom playback-delay-custom--inline">
              <div className="playback-delay-custom__field">
                <input
                  ref={customInputRef}
                  id="playback-delay-custom-min"
                  type="text"
                  inputMode="decimal"
                  className="playback-delay-custom__input"
                  placeholder={t('player.delayCustomPlaceholder')}
                  value={customMinutes}
                  onChange={e => setCustomMinutes(e.target.value)}
                  aria-label={t('player.delayCustomMinutes')}
                />
                <span className="playback-delay-custom__suffix" aria-hidden="true">min</span>
              </div>
              <button
                type="button"
                className="btn btn-primary"
                disabled={customSeconds == null}
                aria-label={canPauseLater ? t('player.delaySchedulePause') : t('player.delayScheduleStart')}
                onClick={() => { if (customSeconds != null) apply(customSeconds); }}
              >
                {t('player.delayApply')}
              </button>
            </div>

            <div
              className="playback-delay-preview"
              aria-live="polite"
              data-empty={previewClock == null ? 'true' : 'false'}
            >
              {previewClock != null && (
                <>
                  <span className="playback-delay-preview__label">
                    {canPauseLater ? t('player.delayPreviewPause') : t('player.delayPreviewStart')}
                  </span>
                  <span className="playback-delay-preview__time">{previewClock}</span>
                </>
              )}
            </div>
          </>
        )}

        {!canPauseLater && !canStartLater && (
          <div className="playback-delay-idle">
            <p className="playback-delay-muted">{t('player.delayInactivePause')}</p>
            <p className="playback-delay-muted">{t('player.delayInactiveStart')}</p>
          </div>
        )}
      </div>
    </div>,
    document.body,
  );
}
