"use client"

import type { ISegmentEditModalProps } from "./SegmentEditModal.d"
import type { JSX } from "react"

import { LoaderCircle, Pause, Play, Scissors } from "lucide-react"
import { FunctionComponent, useCallback, useEffect, useMemo, useRef, useState } from "react"

import { Button, Modal } from "@shared/ui"
import {
	type EditorSegment,
	secondsToTimecode,
	splitSegmentAtMarkers,
} from "@shared/lib/transcriptionDocument"
import { SegmentSplitter } from "@features/project/SegmentSplitter"

import styles from "./SegmentEditModal.module.scss"

const SegmentPlayer: FunctionComponent<{
	videoUrl: string
	start: number
	end: number
}> = ({ videoUrl, start, end }) => {
	const videoRef = useRef<HTMLVideoElement>(null)
	const trackRef = useRef<HTMLDivElement>(null)
	const rafRef = useRef<number>(0)
	const [currentTime, setCurrentTime] = useState(start)
	const [playing, setPlaying] = useState(false)
	const [dragging, setDragging] = useState(false)

	const duration = end - start
	const progress =
		duration > 0
			? Math.min(Math.max((currentTime - start) / duration, 0), 1)
			: 0

	/* Time tracking via rAF — only runs while playing or dragging */
	useEffect(() => {
		if (!playing && !dragging) return
		const video = videoRef.current
		if (!video) return

		const tick = () => {
			setCurrentTime(video.currentTime)
			if (video.currentTime >= end && !video.paused) {
				video.pause()
				setPlaying(false)
			}
			rafRef.current = requestAnimationFrame(tick)
		}
		rafRef.current = requestAnimationFrame(tick)
		return () => cancelAnimationFrame(rafRef.current)
	}, [playing, dragging, end])

	/* Set initial time once video is ready */
	useEffect(() => {
		const video = videoRef.current
		if (!video) return
		const onLoaded = () => {
			video.currentTime = start
		}
		video.addEventListener("loadedmetadata", onLoaded)
		if (video.readyState >= 1) onLoaded()
		return () => video.removeEventListener("loadedmetadata", onLoaded)
	}, [start])

	const togglePlay = useCallback(() => {
		const video = videoRef.current
		if (!video) return
		if (video.paused) {
			if (video.currentTime >= end) video.currentTime = start
			video.play()
			setPlaying(true)
		} else {
			video.pause()
			setPlaying(false)
		}
	}, [start, end])

	const seekToPosition = useCallback(
		(clientX: number) => {
			const track = trackRef.current
			const video = videoRef.current
			if (!track || !video || duration <= 0) return
			const rect = track.getBoundingClientRect()
			const fraction = Math.min(
				Math.max((clientX - rect.left) / rect.width, 0),
				1,
			)
			video.currentTime = start + fraction * duration
		},
		[start, duration],
	)

	const handleTrackMouseDown = useCallback(
		(e: React.MouseEvent) => {
			e.preventDefault()
			setDragging(true)
			seekToPosition(e.clientX)
		},
		[seekToPosition],
	)

	useEffect(() => {
		if (!dragging) return
		const handleMouseMove = (e: MouseEvent) => seekToPosition(e.clientX)
		const handleMouseUp = () => setDragging(false)
		window.addEventListener("mousemove", handleMouseMove)
		window.addEventListener("mouseup", handleMouseUp)
		return () => {
			window.removeEventListener("mousemove", handleMouseMove)
			window.removeEventListener("mouseup", handleMouseUp)
		}
	}, [dragging, seekToPosition])

	return (
		<div className={styles.playerWrapper}>
			<div className={styles.videoArea}>
				<video
					ref={videoRef}
					src={videoUrl}
					crossOrigin="anonymous"
					playsInline
					preload="auto"
					className={styles.video}
				/>
				<button
					type="button"
					className={styles.playButton}
					onClick={togglePlay}
				>
					{playing ? <Pause size={24} /> : <Play size={24} />}
				</button>
				<div className={styles.timeRange}>
					{secondsToTimecode(start)} — {secondsToTimecode(end)}
				</div>
			</div>
			<div className={styles.segmentControls}>
				<span className={styles.segmentTime}>
					{secondsToTimecode(Math.max(currentTime, start))}
				</span>
				<div
					className={styles.segmentTrack}
					ref={trackRef}
					onMouseDown={handleTrackMouseDown}
				>
					<div
						className={styles.segmentTrackFill}
						style={{ width: `${progress * 100}%` }}
					/>
					<div
						className={styles.segmentTrackThumb}
						style={{ left: `${progress * 100}%` }}
					/>
				</div>
				<span className={styles.segmentTime}>
					{secondsToTimecode(end)}
				</span>
			</div>
		</div>
	)
}

export const SegmentEditModal: FunctionComponent<
	ISegmentEditModalProps
> = ({ open, onOpenChange, videoUrl, segment, onSave, onSplit }): JSX.Element => {
	const [text, setText] = useState(segment.text)
	const [saving, setSaving] = useState(false)
	const [splitMode, setSplitMode] = useState(false)

	const canSplit = !!onSplit && !!segment.words && segment.words.length >= 2

	useEffect(() => {
		if (open) {
			setText(segment.text)
			setSplitMode(false)
		}
	}, [open, segment.text])

	const editorSegment: EditorSegment = useMemo(
		() => ({
			startTime: secondsToTimecode(segment.start),
			endTime: secondsToTimecode(segment.end),
			text: segment.text,
			words: segment.words,
		}),
		[segment],
	)

	const handleSave = useCallback(async () => {
		setSaving(true)
		try {
			await onSave(text)
			onOpenChange(false)
		} finally {
			setSaving(false)
		}
	}, [text, onSave, onOpenChange])

	const handleSplit = useCallback(
		async (newSegments: EditorSegment[]) => {
			if (!onSplit) return
			setSaving(true)
			try {
				await onSplit(
					newSegments.map((s) => ({
						start: s.words?.[0]?.start ?? segment.start,
						end: s.words?.[s.words.length - 1]?.end ?? segment.end,
						text: s.text,
						words: s.words,
					})),
				)
				onOpenChange(false)
			} finally {
				setSaving(false)
			}
		},
		[onSplit, onOpenChange, segment],
	)

	const handleKeyDown = useCallback(
		(e: React.KeyboardEvent<HTMLTextAreaElement>) => {
			if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
				e.preventDefault()
				handleSave()
			}
		},
		[handleSave],
	)

	return (
		<Modal
			open={open}
			onOpenChange={onOpenChange}
			title="Редактировать субтитр"
		>
			<div className={styles.root} data-testid="SegmentEditModal">
				{videoUrl && (
					<SegmentPlayer
						videoUrl={videoUrl}
						start={segment.start}
						end={segment.end}
					/>
				)}

				{splitMode ? (
					<SegmentSplitter
						segment={editorSegment}
						onSplit={handleSplit}
						onCancel={() => setSplitMode(false)}
					/>
				) : (
					<>
						<textarea
							className={styles.textArea}
							value={text}
							onChange={(e) => setText(e.target.value)}
							onKeyDown={handleKeyDown}
							rows={3}
							placeholder="Текст субтитра..."
							autoFocus
						/>

						<div className={styles.actions}>
							{canSplit && (
								<Button
									type="button"
									variant="outline"
									onClick={() => setSplitMode(true)}
									className={styles.splitAction}
								>
									<Scissors size={14} />
									Разделить
								</Button>
							)}
							<div className={styles.actionsSpacer} />
							<Button
								type="button"
								variant="outline"
								onClick={() => onOpenChange(false)}
								disabled={saving}
							>
								Отмена
							</Button>
							<Button
								type="button"
								variant="primary"
								onClick={handleSave}
								disabled={saving}
							>
								{saving ? (
									<LoaderCircle size={16} className={styles.spinner} />
								) : null}
								Сохранить
							</Button>
						</div>
					</>
				)}
			</div>
		</Modal>
	)
}
