/* eslint-disable spellcheck/spell-checker */
'use client';

import React, { useEffect, useRef, useState } from 'react';
import { notification } from 'antd';
import {
  PlayCircleFilled,
  PauseCircleFilled,
  SoundOutlined,
  AudioMutedOutlined,
  FullscreenOutlined,
  FullscreenExitOutlined,
} from '@ant-design/icons';
import { updateTrainingVideoStatus } from '@/app/auth/service';
import { type TrainingVideoDefinition } from './constants';
import { clampPercent, formatTime } from './utils';

const PROGRESS_SAVE_INTERVAL_MS = 10000;
const SEEK_TOLERANCE_SECONDS = 1;

interface TrainingVideoPlayerProps {
  video: TrainingVideoDefinition
  videoIndex: number
  // Seeds the resume position and the completed/scrub-lock state on mount. To reflect a
  // changed value later, remount the player with a `key` (see TrainingVideoGate/OnboardingPage).
  initialProgress: number
  onProgressChange?: (videoIndex: number, percent: number) => void
  onCompleted?: (videoIndex: number) => void
}

const TrainingVideoPlayer: React.FC<TrainingVideoPlayerProps> = ({ video, videoIndex, initialProgress, onProgressChange, onCompleted }) => {
  const videoRef = useRef<HTMLVideoElement>(null);
  const containerRef = useRef<HTMLDivElement>(null);

  const [progress, setProgress] = useState<number>(() => clampPercent(initialProgress));
  const [currentTime, setCurrentTime] = useState<number>(0);
  const [duration, setDuration] = useState<number>(0);
  const [isPlaying, setIsPlaying] = useState<boolean>(false);
  const [isMuted, setIsMuted] = useState<boolean>(false);
  const [volume, setVolume] = useState<number>(1);
  const [isFullscreen, setIsFullscreen] = useState<boolean>(false);
  const [hasStarted, setHasStarted] = useState<boolean>(false);
  const lastSavedAtRef = useRef<number>(0);
  const hasResumedRef = useRef<boolean>(false);
  const maxWatchedTimeRef = useRef<number>(0);

  // Once a video has been fully watched once, the skip restriction no longer serves a
  // purpose - let the user freely scrub through it to review any part.
  const isCompleted = progress >= 100;
  const seekPercent = duration > 0 ? (currentTime / duration) * 100 : 0;
  const volumePercent = (isMuted ? 0 : volume) * 100;
  const sliderTrackStyle = (percent: number): React.CSSProperties => ({
    background: `linear-gradient(to right, #3b82f6 0%, #3b82f6 ${percent}%, #ffffff ${percent}%, #ffffff 100%)`,
  });

  useEffect(() => {
    const handleFullscreenChange = (): void => {
      setIsFullscreen(document.fullscreenElement === containerRef.current);
    };
    document.addEventListener('fullscreenchange', handleFullscreenChange);
    return () => {
      document.removeEventListener('fullscreenchange', handleFullscreenChange);
    };
  }, []);

  const reportProgress = (percent: number): void => {
    setProgress((prev) => Math.max(prev, percent));
    onProgressChange?.(videoIndex, percent);
  };

  const saveProgress = (value: number): void => {
    updateTrainingVideoStatus({ videoIndex, progress: value }).catch(() => {
      // Progress persistence is best-effort; playback isn't blocked by it.
    });
  };

  const handleLoadedMetadata = (event: React.SyntheticEvent<HTMLVideoElement>): void => {
    const el = event.currentTarget;
    setDuration(el.duration);
    el.volume = volume;
    el.muted = isMuted;
    if (hasResumedRef.current) return;
    hasResumedRef.current = true;

    if (progress > 0 && progress < 100 && el.duration) {
      const resumeTime = (progress / 100) * el.duration;
      maxWatchedTimeRef.current = resumeTime;
      el.currentTime = resumeTime;
    }
  };

  const handleTimeUpdate = (event: React.SyntheticEvent<HTMLVideoElement>): void => {
    const el = event.currentTarget;
    setCurrentTime(el.currentTime);
    if (!el.duration) return;

    if (el.currentTime > maxWatchedTimeRef.current) {
      maxWatchedTimeRef.current = el.currentTime;
    }

    const percent = Math.round((el.currentTime / el.duration) * 100);
    reportProgress(percent);

    const now = Date.now();
    if (now - lastSavedAtRef.current > PROGRESS_SAVE_INTERVAL_MS) {
      lastSavedAtRef.current = now;
      saveProgress(percent);
    }
  };

  // Defense in depth: if currentTime is ever moved forward outside of normal playback
  // (e.g. via devtools), snap it back to the furthest point actually watched. Skipped once
  // this video has been fully watched - free scrubbing is allowed for review.
  const handleSeeking = (event: React.SyntheticEvent<HTMLVideoElement>): void => {
    if (isCompleted) return;
    const el = event.currentTarget;
    if (el.currentTime > maxWatchedTimeRef.current + SEEK_TOLERANCE_SECONDS) {
      el.currentTime = maxWatchedTimeRef.current;
    }
  };

  const handlePause = (event: React.SyntheticEvent<HTMLVideoElement>): void => {
    const el = event.currentTarget;
    setIsPlaying(false);
    if (!el.duration) return;
    const percent = Math.round((el.currentTime / el.duration) * 100);
    reportProgress(percent);
    saveProgress(percent);
  };

  const handlePlay = (): void => {
    setHasStarted(true);
    setIsPlaying(true);
  };

  const handleEnded = (): void => {
    setIsPlaying(false);
    reportProgress(100);
    updateTrainingVideoStatus({ videoIndex, completed: true }).catch(() => {
      notification.error({
        message: 'Error',
        description: 'Could not save your training video completion. Please try replaying it.',
      });
    });
    onCompleted?.(videoIndex);
  };

  const togglePlayPause = (): void => {
    const el = videoRef.current;
    if (!el) return;
    if (el.paused) {
      void el.play();
    } else {
      el.pause();
    }
  };

  const toggleMute = (): void => {
    const el = videoRef.current;
    if (!el) return;
    el.muted = !el.muted;
    setIsMuted(el.muted);
  };

  const handleVolumeChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
    const el = videoRef.current;
    const value = Number(event.target.value);
    setVolume(value);
    if (!el) return;
    el.volume = value;
    el.muted = value === 0;
    setIsMuted(value === 0);
  };

  const handleSeekBarChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
    const el = videoRef.current;
    const value = Number(event.target.value);
    setCurrentTime(value);
    if (el) el.currentTime = value;
  };

  const toggleFullscreen = (): void => {
    if (isFullscreen) {
      void document.exitFullscreen();
    } else {
      void containerRef.current?.requestFullscreen();
    }
  };

  return (
    <div ref={containerRef} className="relative aspect-video overflow-hidden rounded-xl border border-slate-100 bg-black">
      <style jsx>{`
        .training-video-slider::-webkit-slider-thumb {
          -webkit-appearance: none;
          appearance: none;
          width: 12px;
          height: 12px;
          border-radius: 9999px;
          background: #ffffff;
          box-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
          cursor: pointer;
        }
        .training-video-slider::-moz-range-thumb {
          width: 12px;
          height: 12px;
          border: none;
          border-radius: 9999px;
          background: #ffffff;
          box-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
          cursor: pointer;
        }
        .training-video-slider::-moz-range-track {
          background: transparent;
        }
      `}</style>

      <video
        ref={videoRef}
        disablePictureInPicture
        preload="auto"
        className="h-full w-full cursor-pointer"
        onClick={togglePlayPause}
        onContextMenu={(event) => event.preventDefault()}
        onLoadedMetadata={handleLoadedMetadata}
        onDurationChange={(event) => setDuration(event.currentTarget.duration)}
        onTimeUpdate={handleTimeUpdate}
        onSeeking={handleSeeking}
        onPause={handlePause}
        onPlay={handlePlay}
        onEnded={handleEnded}
      >
        <source src={video.url} />
      </video>

      {!isPlaying && (
        <button
          type="button"
          onClick={togglePlayPause}
          className="absolute inset-0 flex h-full w-full cursor-pointer items-center justify-center border-0 bg-transparent"
        >
          <span className="flex h-16 w-16 items-center justify-center rounded-full bg-blue-600/90 text-white shadow-lg transition hover:bg-blue-600">
            <PlayCircleFilled style={{ fontSize: 30 }} />
          </span>
        </button>
      )}

      {hasStarted && (
        <div className="absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/80 to-transparent px-4 pb-3 pt-6">
          {isCompleted ? (
            // Fully watched already - let the user scrub freely to review any part.
            <input
              type="range"
              min={0}
              max={duration || 0}
              step={0.1}
              value={currentTime}
              onChange={handleSeekBarChange}
              style={sliderTrackStyle(seekPercent)}
              className="training-video-slider mb-2 h-1.5 w-full cursor-pointer appearance-none rounded-full"
            />
          ) : (
            // Visual-only indicator: no click/drag handlers, so it can't be used to skip ahead
            <div className="mb-2 h-1.5 w-full overflow-hidden rounded-full bg-white">
              <div className="h-full rounded-full bg-blue-500" style={{ width: `${progress}%` }} />
            </div>
          )}
          <div className="flex items-center justify-between text-white">
            <div className="flex items-center gap-3">
              <button type="button" onClick={togglePlayPause} className="cursor-pointer border-0 bg-transparent text-white">
                {isPlaying ? <PauseCircleFilled style={{ fontSize: 22 }} /> : <PlayCircleFilled style={{ fontSize: 22 }} />}
              </button>
              <span className="text-xs tabular-nums text-white/90">
                {formatTime(currentTime)} / {formatTime(duration)}
              </span>
            </div>
            <div className="flex items-center gap-2">
              <button type="button" onClick={toggleMute} className="cursor-pointer border-0 bg-transparent text-white">
                {isMuted || volume === 0 ? <AudioMutedOutlined style={{ fontSize: 18 }} /> : <SoundOutlined style={{ fontSize: 18 }} />}
              </button>
              <input
                type="range"
                min={0}
                max={1}
                step={0.05}
                value={isMuted ? 0 : volume}
                onChange={handleVolumeChange}
                style={sliderTrackStyle(volumePercent)}
                className="training-video-slider h-1 w-16 cursor-pointer appearance-none rounded-full"
              />
              <button type="button" onClick={toggleFullscreen} className="cursor-pointer border-0 bg-transparent text-white">
                {isFullscreen ? <FullscreenExitOutlined style={{ fontSize: 18 }} /> : <FullscreenOutlined style={{ fontSize: 18 }} />}
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
};

export default TrainingVideoPlayer;
