/**
 * AttachmentVideo — custom video player with Fluxer-style overlay
 * controls. Ported from the new UI and adapted for our pipeline:
 * takes the already-decrypted blob URL from `EncryptedAttachment`.
 *
 * Two playback states:
 *   1. Not started → poster + center play button.
 *   2. Playing → bottom seek bar, play/pause, mute, time, fullscreen.
 *
 * Top-right hover bar surfaces Download regardless of playback state.
 */
import { useCallback, useEffect, useRef, useState } from 'react';
import {
	CornersIn,
	CornersOut,
	Download,
	Pause,
	Play,
	SpeakerHigh,
	SpeakerSlash,
	Star,
} from '@phosphor-icons/react';
import { useMutation, useQuery } from 'convex/react';
import { api } from '../../../../../convex/_generated/api';
import type { Id } from '../../../../../convex/_generated/dataModel';
import type { AttachmentMetadata } from './EncryptedAttachment';
import styles from './AttachmentVideo.module.css';

interface AttachmentVideoProps {
	src: string;
	filename: string;
	width?: number;
	height?: number;
	attachment?: AttachmentMetadata;
}

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

export function AttachmentVideo({
	src,
	filename,
	width,
	height,
	attachment,
}: AttachmentVideoProps) {
	const wrapperRef = useRef<HTMLDivElement>(null);
	const videoRef = useRef<HTMLVideoElement>(null);

	const [hasStarted, setHasStarted] = useState(false);
	const [isPlaying, setIsPlaying] = useState(false);
	const [currentTime, setCurrentTime] = useState(0);
	const [duration, setDuration] = useState(0);
	const [volume, setVolume] = useState(1);
	const [isMuted, setIsMuted] = useState(false);
	const [isFullscreen, setIsFullscreen] = useState(false);

	// Saved-media wiring — mirrors ImageLightbox / AttachmentAudio
	// so video attachments can be bookmarked into the Media tab.
	const myUserId =
		typeof localStorage !== 'undefined' ? localStorage.getItem('userId') : null;
	const savedList = useQuery(
		api.savedMedia.list,
		myUserId && attachment
			? { userId: myUserId as Id<'userProfiles'> }
			: 'skip',
	);
	const isSaved = !!(
		attachment && savedList?.some((m) => m.url === attachment.url)
	);
	const saveMutation = useMutation(api.savedMedia.save);
	const removeMutation = useMutation(api.savedMedia.remove);

	const handleToggleSaved = useCallback(async () => {
		if (!attachment || !myUserId) return;
		try {
			if (isSaved) {
				await removeMutation({
					userId: myUserId as Id<'userProfiles'>,
					url: attachment.url,
				});
			} else {
				await saveMutation({
					userId: myUserId as Id<'userProfiles'>,
					url: attachment.url,
					kind: attachment.mimeType.split('/')[0],
					filename: attachment.filename,
					mimeType: attachment.mimeType,
					width: attachment.width,
					height: attachment.height,
					size: attachment.size,
					encryptionKey: attachment.key,
					encryptionIv: attachment.iv,
				});
			}
		} catch (err) {
			console.warn('Failed to toggle saved video:', err);
		}
	}, [attachment, isSaved, myUserId, removeMutation, saveMutation]);

	const widthCap = Math.min(width || 400, 400);
	const heightCap = Math.min(height || 300, 300);

	useEffect(() => {
		const el = videoRef.current;
		if (!el) return;
		const onTime = () => setCurrentTime(el.currentTime);
		const onDur = () => setDuration(el.duration);
		const onPlay = () => setIsPlaying(true);
		const onPause = () => setIsPlaying(false);
		const onEnded = () => setIsPlaying(false);
		const onVol = () => {
			setVolume(el.volume);
			setIsMuted(el.muted);
		};
		el.addEventListener('timeupdate', onTime);
		el.addEventListener('loadedmetadata', onDur);
		el.addEventListener('durationchange', onDur);
		el.addEventListener('play', onPlay);
		el.addEventListener('pause', onPause);
		el.addEventListener('ended', onEnded);
		el.addEventListener('volumechange', onVol);
		return () => {
			el.removeEventListener('timeupdate', onTime);
			el.removeEventListener('loadedmetadata', onDur);
			el.removeEventListener('durationchange', onDur);
			el.removeEventListener('play', onPlay);
			el.removeEventListener('pause', onPause);
			el.removeEventListener('ended', onEnded);
			el.removeEventListener('volumechange', onVol);
		};
	}, []);

	useEffect(() => {
		const handler = () => {
			setIsFullscreen(document.fullscreenElement === wrapperRef.current);
		};
		document.addEventListener('fullscreenchange', handler);
		return () => document.removeEventListener('fullscreenchange', handler);
	}, []);

	const handleStartPlay = useCallback(() => {
		const el = videoRef.current;
		if (!el) return;
		setHasStarted(true);
		void el.play().catch(() => {});
	}, []);

	const handleTogglePlay = useCallback(() => {
		const el = videoRef.current;
		if (!el) return;
		if (el.paused) void el.play().catch(() => {});
		else el.pause();
	}, []);

	const handleSeek = useCallback(
		(e: React.ChangeEvent<HTMLInputElement>) => {
			const el = videoRef.current;
			if (!el) return;
			const next = Number(e.target.value);
			el.currentTime = next;
			setCurrentTime(next);
		},
		[],
	);

	const handleToggleMute = useCallback(() => {
		const el = videoRef.current;
		if (!el) return;
		if (el.muted && el.volume === 0) el.volume = 1;
		el.muted = !el.muted;
	}, []);

	const handleToggleFullscreen = useCallback(() => {
		const wrapper = wrapperRef.current;
		if (!wrapper) return;
		if (document.fullscreenElement) {
			void document.exitFullscreen().catch(() => {});
		} else {
			void wrapper.requestFullscreen().catch(() => {});
		}
	}, []);

	const handleDownload = useCallback(() => {
		if (!src) return;
		const a = document.createElement('a');
		a.href = src;
		a.download = filename;
		document.body.appendChild(a);
		a.click();
		document.body.removeChild(a);
	}, [src, filename]);

	const stop =
		(fn: () => void) =>
		(e: React.MouseEvent) => {
			e.stopPropagation();
			fn();
		};

	const progressRatio = duration > 0 ? currentTime / duration : 0;
	const progressPercent = `${Math.max(0, Math.min(100, progressRatio * 100)).toFixed(2)}%`;

	return (
		<div
			ref={wrapperRef}
			className={`${styles.wrapper} ${hasStarted ? styles.wrapperPlaying : ''}`}
			style={{
				maxWidth: `min(${widthCap}px, 100%)`,
				maxHeight: `${heightCap}px`,
			}}
		>
			<video
				ref={videoRef}
				src={src || undefined}
				className={styles.video}
				preload="metadata"
				playsInline
				muted={!hasStarted}
				onClick={hasStarted ? handleTogglePlay : undefined}
			/>

			<div className={styles.topBar}>
				{attachment && (
					<button
						type="button"
						className={styles.topBarButton}
						onClick={stop(() => void handleToggleSaved())}
						aria-label={isSaved ? 'Unfavorite' : 'Favorite'}
						title={isSaved ? 'Unfavorite' : 'Favorite'}
						style={
							isSaved
								? { color: 'var(--brand-primary, #5865f2)' }
								: undefined
						}
					>
						<Star size={18} weight={isSaved ? 'fill' : 'regular'} />
					</button>
				)}
				<button
					type="button"
					className={styles.topBarButton}
					onClick={stop(handleDownload)}
					disabled={!src}
					aria-label="Download"
					title="Download"
				>
					<Download size={18} weight="regular" />
				</button>
			</div>

			{!hasStarted && (
				<button
					type="button"
					className={styles.playOverlay}
					onClick={handleStartPlay}
					aria-label="Play video"
				>
					<span className={styles.playBadge}>
						<Play size={22} weight="fill" />
					</span>
				</button>
			)}

			{hasStarted && (
				<div
					className={styles.bottomBar}
					onClick={(e) => e.stopPropagation()}
				>
					<div
						className={styles.seekTrack}
						style={{ ['--progress' as string]: progressPercent }}
					>
						<div className={styles.seekFill} />
						<input
							type="range"
							className={styles.seekInput}
							min={0}
							max={duration || 0}
							step={0.01}
							value={currentTime}
							onChange={handleSeek}
							disabled={!duration}
							aria-label="Seek video"
						/>
					</div>

					<div className={styles.controlsRow}>
						<button
							type="button"
							className={styles.controlButton}
							onClick={handleTogglePlay}
							aria-label={isPlaying ? 'Pause' : 'Play'}
							title={isPlaying ? 'Pause' : 'Play'}
						>
							{isPlaying ? (
								<Pause size={18} weight="fill" />
							) : (
								<Play size={18} weight="fill" />
							)}
						</button>

						<button
							type="button"
							className={styles.controlButton}
							onClick={handleToggleMute}
							aria-label={isMuted || volume === 0 ? 'Unmute' : 'Mute'}
							title={isMuted || volume === 0 ? 'Unmute' : 'Mute'}
						>
							{isMuted || volume === 0 ? (
								<SpeakerSlash size={18} weight="fill" />
							) : (
								<SpeakerHigh size={18} weight="fill" />
							)}
						</button>

						<span className={styles.timeLabel}>
							{formatTime(currentTime)} / {formatTime(duration)}
						</span>

						<div className={styles.controlsSpacer} />

						<button
							type="button"
							className={styles.controlButton}
							onClick={handleToggleFullscreen}
							aria-label={
								isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'
							}
							title={isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'}
						>
							{isFullscreen ? (
								<CornersIn size={18} weight="bold" />
							) : (
								<CornersOut size={18} weight="bold" />
							)}
						</button>
					</div>
				</div>
			)}
		</div>
	);
}
