"use client"

import type { IVerifyStepProps } from "./VerifyStep.d"
import type { JSX } from "react"

import { MediaPlayer, MediaProvider } from "@vidstack/react"
import {
	defaultLayoutIcons,
	DefaultVideoLayout,
} from "@vidstack/react/player/layouts/default"

import "@vidstack/react/player/styles/default/theme.css"
import "@vidstack/react/player/styles/default/layouts/video.css"

import {
	AlertTriangle,
	CheckCircle,
	FileVideo,
	HardDrive,
	Info,
	Monitor,
	Music,
	RefreshCw,
} from "lucide-react"
import {
	FunctionComponent,
	useCallback,
	useEffect,
	useMemo,
	useState,
} from "react"

import cs from "classnames"

import api from "@shared/api"
import { useWizard } from "@shared/context/WizardContext"
import { useTaskProgressState } from "@shared/hooks/useTaskProgressState"
import { Badge, Button, CircularProgress } from "@shared/ui"
import { StaticLoader } from "@shared/ui/Loader"

import { buildCancelJobPayload, useCancelJob } from "../useCancelJob"
import styles from "./VerifyStep.module.scss"

function formatFileSize(bytes: number): string {
	if (bytes < 1024) return `${bytes} Б`
	if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} КБ`
	if (bytes < 1024 * 1024 * 1024)
		return `${(bytes / (1024 * 1024)).toFixed(1)} МБ`
	return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} ГБ`
}

const ERROR_CONVERT_FAILED = "Не удалось запустить конвертацию"

export const VerifyStep: FunctionComponent<IVerifyStepProps> = ({
	className,
}): JSX.Element => {
	const {
		primaryFileKey,
		videoUrl,
		originalFileName,
		activeJobId,
		activeJobType,
		goBack,
		confirmVerify,
		setFileKey,
		setActiveJob,
		startMediaConvert,
	} = useWizard()

	const [convertError, setConvertError] = useState<string | null>(null)
	const { mutate: cancelJob, isPending: isCancelling } = useCancelJob()

	/* Derive conversion state from wizard-persisted activeJob */
	const convertJobId = activeJobType === "MEDIA_CONVERT" ? activeJobId : null
	const convertStatus: "idle" | "converting" | "failed" = convertJobId
		? "converting"
		: convertError
			? "failed"
			: "idle"

	const { data: probeData, isPending: isProbing } = api.useQuery(
		"get",
		"/api/media/get_meta/",
		{ params: { query: { file_path: primaryFileKey ?? "" } } },
		{ enabled: !!primaryFileKey },
	)

	const mediaInfo = useMemo(() => {
		if (!probeData) return null
		const videoStream = probeData.streams?.find((s) => s.codec_type === "video")
		const audioStream = probeData.streams?.find((s) => s.codec_type === "audio")
		const format = probeData.format
		const rawName = originalFileName ?? primaryFileKey?.split("/").pop() ?? null
		const actualFileName = primaryFileKey?.split("/").pop() ?? rawName
		const ext = actualFileName?.split(".").pop()?.toUpperCase() ?? null
		return {
			filename: rawName,
			size: format?.size ? Number(format.size) : null,
			formatName: ext,
			width: videoStream?.width ?? null,
			height: videoStream?.height ?? null,
			audioCodec: audioStream?.codec_name ?? null,
		}
	}, [probeData, originalFileName, primaryFileKey])

	const needsConversion = useMemo(() => {
		if (!mediaInfo?.formatName) return false
		return mediaInfo.formatName !== "MP4"
	}, [mediaInfo])

	/* ---- Conversion logic ---- */

	const handleConvert = useCallback(() => {
		void startMediaConvert().catch(() => {
			setConvertError(ERROR_CONVERT_FAILED)
		})
	}, [startMediaConvert])

	const {
		progressPct: convertProgressPct,
		message: convertMessage,
		status: convertTaskStatus,
		errorMessage: convertErrorMessage,
	} = useTaskProgressState({
		jobId: convertJobId,
		enabled: !!convertJobId && convertStatus === "converting",
		defaultMessage: "Конвертация видео...",
	})

	useEffect(() => {
		if (!convertJobId || convertStatus !== "converting") return

		if (convertTaskStatus === "FAILED") {
			setActiveJob(null)
			setConvertError(convertErrorMessage ?? "Ошибка конвертации")
		}
	}, [convertErrorMessage, convertJobId, convertStatus, convertTaskStatus, setActiveJob])

	/* ---- Handlers ---- */

	const handleReplace = () => {
		void setFileKey(null, null, null)
	}

	const handleNext = () => {
		void confirmVerify()
	}

	/* ---- Converting view ---- */

	if (convertStatus === "converting") {
		return (
			<div className={cs(styles.root, className)} data-testid="VerifyStep">
				<div className={styles.convertingContent}>
					<div className={styles.progressWrapper}>
						<CircularProgress
							percentage={convertProgressPct}
							size={200}
							strokeWidth={8}
							color="var(--color-success)"
							className={styles.circle}
							bgClassName={styles.circleBg}
							valueClassName={styles.circleValue}
						/>
						<div className={styles.progressInner}>
							<span className={styles.percentage}>
								{Math.round(convertProgressPct)}%
							</span>
							<span className={styles.statusLabel}>КОНВЕРТАЦИЯ</span>
						</div>
					</div>

					<p className={styles.convertDescription}>{convertMessage}</p>

					<div className={styles.convertInfoCard}>
						<Info size={16} className={styles.convertInfoIcon} />
						<span>
							Конвертация выполняется на сервере. Вы можете покинуть страницу —
							прогресс сохранится.
						</span>
					</div>

					<Button
						variant="danger"
						size="sm"
						onClick={() => {
							if (!convertJobId || isCancelling) return

							cancelJob(buildCancelJobPayload(convertJobId), {
								onSuccess: () => {
									setActiveJob(null)
								},
							})
						}}
						disabled={isCancelling}
					>
						{isCancelling ? "Отмена..." : "Отменить конвертацию"}
					</Button>
				</div>
			</div>
		)
	}

	/* ---- Normal / needs-conversion view ---- */

	return (
		<div className={cs(styles.root, className)} data-testid="VerifyStep">
			<div className={styles.layout}>
				{/* Video player */}
				<div className={styles.playerWrapper}>
					{isProbing && primaryFileKey ? (
						<div className={styles.placeholder}>
							<StaticLoader block description="Анализ видеофайла..." />
						</div>
					) : needsConversion ? (
						<div className={styles.placeholder}>
							<FileVideo size={48} />
							<p>Формат {mediaInfo?.formatName ?? ""} не поддерживается</p>
							<Button
								variant="primary"
								size="sm"
								onClick={handleConvert}
								disabled={!primaryFileKey}
							>
								Конвертировать в MP4
							</Button>
						</div>
					) : videoUrl ? (
						<MediaPlayer src={videoUrl} crossOrigin="" playsInline>
							<MediaProvider />
							<DefaultVideoLayout icons={defaultLayoutIcons} />
						</MediaPlayer>
					) : (
						<div className={styles.placeholder}>
							<FileVideo size={48} />
							<p>Видео не загружено</p>
						</div>
					)}
				</div>

				{/* Info sidebar */}
				<div className={styles.sidebar}>
					<div className={styles.statusRow}>
						{isProbing && primaryFileKey ? (
							<Badge variant="info">
								<Info size={14} />
								Анализ файла...
							</Badge>
						) : needsConversion ? (
							<Badge variant="warning">
								<AlertTriangle size={14} />
								Требуется конвертация
							</Badge>
						) : (
							<Badge variant="success">
								<CheckCircle size={14} />
								Готово к обработке
							</Badge>
						)}
					</div>

					<div className={styles.infoCards}>
						<div className={styles.infoCard}>
							<FileVideo size={16} className={styles.infoIcon} />
							<div className={styles.infoContent}>
								<span className={styles.infoLabel}>Файл</span>
								<span className={styles.infoValue}>
									{mediaInfo?.filename ?? "—"}
								</span>
							</div>
						</div>
						<div className={styles.infoCard}>
							<HardDrive size={16} className={styles.infoIcon} />
							<div className={styles.infoContent}>
								<span className={styles.infoLabel}>Размер и формат</span>
								<span className={styles.infoValue}>
									{mediaInfo?.size ? formatFileSize(mediaInfo.size) : "—"}{" "}
									&middot; {mediaInfo?.formatName ?? "—"}
								</span>
							</div>
						</div>
						<div className={styles.infoCard}>
							<Monitor size={16} className={styles.infoIcon} />
							<div className={styles.infoContent}>
								<span className={styles.infoLabel}>Разрешение</span>
								<span className={styles.infoValue}>
									{mediaInfo?.width && mediaInfo?.height
										? `${mediaInfo.width}x${mediaInfo.height}`
										: "—"}
								</span>
							</div>
						</div>
						<div className={styles.infoCard}>
							<Music size={16} className={styles.infoIcon} />
							<div className={styles.infoContent}>
								<span className={styles.infoLabel}>Аудиокодек</span>
								<span className={styles.infoValue}>
									{mediaInfo?.audioCodec ?? "—"}
								</span>
							</div>
						</div>
					</div>

					<div className={styles.sidebarActions}>
						{needsConversion ? (
							<>
								{convertError && (
									<p className={styles.convertErrorText}>{convertError}</p>
								)}
								<Button
									variant="primary"
									size="sm"
									onClick={handleConvert}
									disabled={!primaryFileKey}
								>
									Конвертировать в MP4
								</Button>
							</>
						) : null}
						<Button variant="danger" size="sm" onClick={handleReplace}>
							<RefreshCw size={14} />
							Заменить видео
						</Button>
						{!needsConversion && (
							<Button variant="outline" size="sm" disabled>
								Предварительная обрезка
							</Button>
						)}
					</div>
				</div>
			</div>

			{/* Footer */}
			<div className={styles.footer}>
				<Button variant="outline" onClick={goBack}>
					Назад
				</Button>
				<Button
					variant="primary"
					onClick={handleNext}
					disabled={needsConversion}
				>
					Далее: Настройки тишины
				</Button>
			</div>
		</div>
	)
}
