'use client';

import { ExternalLink, Pause, Play, Volume2, VolumeX } from 'lucide-react';
import { useCallback, useEffect, useRef, useState } from 'react';

/**
 * Hero video player tuned for the stubborn-autoplay cases we hit in
 * the field (Chrome with prefers-reduced-motion, data saver, etc.).
 *
 * Three failure modes we defend against:
 *
 *   1. Browser allows muted autoplay — the happy path. Element loads,
 *      starts playing, the `play` event flips `playing` to true and
 *      hides the overlay.
 *
 *   2. Browser blocks autoplay but allows playback on user gesture —
 *      the play overlay sits over the poster, the user clicks, we
 *      call `.load()` first to reset the resource-selection state and
 *      then `.play()` with the user gesture in scope.
 *
 *   3. Browser refuses to play even after the gesture — we catch the
 *      promise rejection and surface a small "open video in a new tab"
 *      link so the visitor isn't completely stuck.
 *
 * Controls: a deliberately subtle bottom bar (play/pause, elapsed time,
 * a seek slider, mute) that stays out of the way — it only fades in on
 * hover (desktop) or tap (touch) and auto-hides ~2.8s after the last
 * interaction while playing; while paused it stays put. The seek slider
 * is a real <input type=range> (keyboard + drag + touch, accessible)
 * laid invisibly over a custom-drawn track so the look matches the rest
 * of the page rather than the chrome of a native control bar.
 *
 * Source order: MP4 only. We previously offered WebM (VP9) first as a
 * size win, but Chrome will pick WebM if listed first, and if that
 * decode fails it does NOT fall back to MP4 — it just sits unloaded.
 */

const CONTROLS_HIDE_MS = 2800;

function formatTime(seconds: number): string {
  if (!Number.isFinite(seconds) || seconds < 0) return '0:00';
  const m = Math.floor(seconds / 60);
  const s = Math.floor(seconds % 60);
  return `${m}:${String(s).padStart(2, '0')}`;
}

export function HeroVideo() {
  const videoRef = useRef<HTMLVideoElement>(null);
  const hideTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
  // Set when the user explicitly pauses — the IntersectionObserver must not
  // restart a video the user chose to stop.
  const userPausedRef = useRef(false);
  const [muted, setMuted] = useState(true);
  const [playing, setPlaying] = useState(false);
  const [playFailed, setPlayFailed] = useState(false);
  const [currentTime, setCurrentTime] = useState(0);
  const [duration, setDuration] = useState(0);
  const [controlsVisible, setControlsVisible] = useState(false);

  useEffect(() => {
    const v = videoRef.current;
    if (!v) return;
    const onPlay = () => {
      setPlaying(true);
      setPlayFailed(false);
    };
    const onPause = () => setPlaying(false);
    const onTime = () => setCurrentTime(v.currentTime);
    const onMeta = () => setDuration(Number.isFinite(v.duration) ? v.duration : 0);
    v.addEventListener('play', onPlay);
    v.addEventListener('pause', onPause);
    v.addEventListener('timeupdate', onTime);
    v.addEventListener('loadedmetadata', onMeta);
    v.addEventListener('durationchange', onMeta);
    // Play only while scrolled into view: with preload="metadata" the 2.6 MB
    // mp4 stays off the critical path until the section is actually visible,
    // and playback pauses again off-screen (saves battery + decode). The
    // .play() attempt is still best-effort — browsers that block autoplay
    // leave the overlay as the user's escape hatch. `userPaused` tracks an
    // explicit pause so the observer doesn't fight the user's choice.
    const io = new IntersectionObserver(
      ([entry]) => {
        if (!entry) return;
        if (entry.isIntersecting) {
          if (!userPausedRef.current && v.paused) v.play().catch(() => undefined);
        } else if (!v.paused) {
          v.pause();
        }
      },
      { threshold: 0.35 },
    );
    io.observe(v);
    return () => {
      io.disconnect();
      v.removeEventListener('play', onPlay);
      v.removeEventListener('pause', onPause);
      v.removeEventListener('timeupdate', onTime);
      v.removeEventListener('loadedmetadata', onMeta);
      v.removeEventListener('durationchange', onMeta);
    };
  }, []);

  // Clear any pending hide timer on unmount.
  useEffect(
    () => () => {
      if (hideTimer.current) clearTimeout(hideTimer.current);
    },
    [],
  );

  const scheduleHide = useCallback(() => {
    if (hideTimer.current) clearTimeout(hideTimer.current);
    hideTimer.current = setTimeout(() => setControlsVisible(false), CONTROLS_HIDE_MS);
  }, []);

  const revealControls = useCallback(() => {
    setControlsVisible(true);
    scheduleHide();
  }, [scheduleHide]);

  const hideControlsNow = useCallback(() => {
    if (hideTimer.current) clearTimeout(hideTimer.current);
    setControlsVisible(false);
  }, []);

  const togglePlay = useCallback(async () => {
    const v = videoRef.current;
    if (!v) return;
    if (v.paused) {
      setPlayFailed(false);
      userPausedRef.current = false;
      try {
        // .load() resets the media element's resource selection — required
        // when an earlier autoplay attempt was blocked before the source
        // ever fetched. Without it, .play() on a stuck element no-ops.
        v.load();
        await v.play();
      } catch {
        setPlayFailed(true);
      }
    } else {
      userPausedRef.current = true;
      v.pause();
    }
  }, []);

  // Click anywhere on the frame toggles playback (YouTube/Vimeo pattern) and
  // reveals the controls — on touch, where there's no hover, this is how the
  // bar surfaces.
  const onVideoClick = useCallback(() => {
    revealControls();
    void togglePlay();
  }, [revealControls, togglePlay]);

  const toggleMute = useCallback((e: React.MouseEvent) => {
    e.stopPropagation();
    const v = videoRef.current;
    if (!v) return;
    const next = !v.muted;
    v.muted = next;
    setMuted(next);
    // Restart from frame 0 whenever the audio state toggles, so the narration
    // and the silent loop both line up with the animation from the top.
    v.currentTime = 0;
    if (v.paused) v.play().catch(() => undefined);
  }, []);

  const onSeek = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    const v = videoRef.current;
    if (!v) return;
    const t = Number(e.currentTarget.value);
    if (!Number.isFinite(t)) return;
    v.currentTime = t;
    setCurrentTime(t);
  }, []);

  const pct = duration > 0 ? Math.min(100, (currentTime / duration) * 100) : 0;
  // Bar shows on hover/tap; while paused it stays up so the scrubber is reachable.
  const barShown = controlsVisible || !playing;

  return (
    <div
      className="absolute inset-0"
      onPointerEnter={revealControls}
      onPointerMove={revealControls}
      onPointerLeave={() => {
        if (playing) hideControlsNow();
      }}
    >
      <video
        ref={videoRef}
        muted
        loop
        playsInline
        preload="metadata"
        poster="/videos/hero-poster.jpg"
        onClick={onVideoClick}
        className="size-full cursor-pointer object-cover"
        aria-label="Animation: a prompt becomes a live MCP server, with secrets staying isolated from the AI pipeline"
      >
        {/* MP4 only — see file-header note on dropping the WebM source. */}
        <source src="/videos/hero.mp4" type="video/mp4" />
      </video>

      {/* PLAY overlay — visible while paused. Full-frame so clicking
          anywhere starts playback. */}
      {!playing && (
        <button
          type="button"
          onClick={onVideoClick}
          aria-label="Play video"
          className="group absolute inset-0 z-10 flex items-center justify-center"
          style={{
            backgroundColor: 'color-mix(in oklab, var(--color-bg) 30%, transparent)',
          }}
        >
          <div
            className="flex size-20 items-center justify-center rounded-full border backdrop-blur transition-transform duration-200 ease-out group-hover:scale-110"
            style={{
              backgroundColor: 'color-mix(in oklab, var(--color-bg-elevated) 80%, transparent)',
              borderColor: 'var(--color-accent)',
              boxShadow: '0 0 32px rgba(99, 102, 241, 0.45), 0 12px 40px rgba(0,0,0,0.55)',
              color: 'var(--color-accent)',
            }}
          >
            {/* translate-x-0.5 optically centres the triangle */}
            <Play size={32} fill="currentColor" className="translate-x-0.5" />
          </div>
        </button>
      )}

      {/* Fallback escape hatch — surfaces only if .play() rejects even after a
          user gesture (extension sandbox, hardware-decoder failures, etc.). */}
      {playFailed && !playing && (
        <a
          href="/videos/hero.mp4"
          target="_blank"
          rel="noopener noreferrer"
          className="absolute inset-x-0 bottom-20 z-20 mx-auto flex w-fit items-center gap-2 rounded-md border px-3 py-2 text-[12px] backdrop-blur hover:text-[--color-fg]"
          style={{
            backgroundColor: 'color-mix(in oklab, var(--color-bg-elevated) 85%, transparent)',
            borderColor: 'var(--color-border-strong)',
            color: 'var(--color-fg-muted)',
          }}
        >
          your browser blocked playback. open the video directly
          <ExternalLink size={12} />
        </a>
      )}

      {/* Controls bar — subtle, reveals on hover/tap, auto-hides while playing.
          pointer-events-none when hidden so it never swallows a frame click. */}
      <div
        className={`absolute inset-x-0 bottom-0 z-30 px-4 pb-3 pt-10 transition-[opacity,transform] duration-200 ease-out ${
          barShown ? 'translate-y-0 opacity-100' : 'pointer-events-none translate-y-1 opacity-0'
        }`}
        style={{
          background:
            'linear-gradient(to top, color-mix(in oklab, var(--color-bg) 72%, transparent), transparent)',
        }}
      >
        <div className="flex items-center gap-3">
          <button
            type="button"
            onClick={(e) => {
              e.stopPropagation();
              revealControls();
              void togglePlay();
            }}
            aria-label={playing ? 'Pause video' : 'Play video'}
            className="inline-flex size-9 shrink-0 items-center justify-center rounded-full border backdrop-blur transition-colors duration-150 hover:text-[--color-fg] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--color-accent]"
            style={{
              backgroundColor: 'color-mix(in oklab, var(--color-bg-elevated) 75%, transparent)',
              borderColor: 'var(--color-border)',
              color: 'var(--color-fg-muted)',
            }}
          >
            {playing ? (
              <Pause size={16} fill="currentColor" />
            ) : (
              <Play size={16} fill="currentColor" className="translate-x-px" />
            )}
          </button>

          <span
            className="mono shrink-0 text-[11px] tabular-nums"
            style={{ color: 'var(--color-fg-muted)' }}
          >
            {formatTime(currentTime)} / {formatTime(duration)}
          </span>

          {/* Seek: custom-drawn rail + fill + thumb, with a transparent native
              range on top carrying all the interaction (drag, touch, keyboard). */}
          <div className="group/seek relative flex h-4 flex-1 items-center">
            <div
              className="h-1 w-full overflow-hidden rounded-full"
              style={{ backgroundColor: 'color-mix(in oklab, var(--color-fg) 22%, transparent)' }}
            >
              <div
                className="h-full rounded-full"
                style={{ width: `${pct}%`, backgroundColor: 'var(--color-accent)' }}
              />
            </div>
            <div
              aria-hidden
              className="pointer-events-none absolute size-3 -translate-x-1/2 rounded-full opacity-0 shadow transition-opacity duration-150 group-hover/seek:opacity-100 group-focus-within/seek:opacity-100"
              style={{ left: `${pct}%`, backgroundColor: 'var(--color-accent)' }}
            />
            <input
              type="range"
              min={0}
              max={duration || 0}
              step="any"
              value={Math.min(currentTime, duration || 0)}
              onChange={onSeek}
              onFocus={revealControls}
              aria-label="Seek video"
              className="absolute inset-0 size-full cursor-pointer appearance-none bg-transparent opacity-0 focus:outline-none"
            />
          </div>

          <button
            type="button"
            onClick={toggleMute}
            aria-label={muted ? 'Unmute video' : 'Mute video'}
            aria-pressed={!muted}
            className="inline-flex size-9 shrink-0 items-center justify-center rounded-full border backdrop-blur transition-colors duration-150 hover:text-[--color-fg] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[--color-accent]"
            style={{
              backgroundColor: 'color-mix(in oklab, var(--color-bg-elevated) 75%, transparent)',
              borderColor: 'var(--color-border)',
              color: muted ? 'var(--color-fg-muted)' : 'var(--color-accent)',
            }}
          >
            {muted ? <VolumeX size={16} /> : <Volume2 size={16} />}
          </button>
        </div>
      </div>
    </div>
  );
}
