import { type CSSProperties, useState } from "react";
import { type TextProps, useWindowDimensions } from "react-native";
import { usePlayer, usePlayerState } from "react-native-omni";
import { useResolveClassNames } from "uniwind";
import type { Chapter } from "~/models";
import { P, Slider, Tooltip } from "~/primitives";
import { useFetch } from "~/query";
import { Info } from "~/ui/info";
import { cn, useQueryState } from "~/utils";
import { seekPlayerTo } from "../imperative";
import { ScrubberTooltip } from "../scrubber";

export const ProgressBar = ({
	chapters,
	seek,
	setSeek,
}: {
	chapters?: Chapter[];
	seek: number | null;
	setSeek: (v: number | null) => void;
}) => {
	const [slug] = useQueryState<string>("slug", undefined!);
	const { data } = useFetch(Info.infoQuery(slug));

	const player = usePlayer();
	// only refresh when the slider would visually move by ~1px (once per second
	// at most), instead of every second regardless of the video's length.
	const { width } = useWindowDimensions();
	const refreshInterval = data?.durationSeconds
		? Math.max(1, data.durationSeconds / width)
		: 1;
	const progress = usePlayerState("currentTime", refreshInterval);
	const buffer = usePlayerState("buffered");

	const [hoverProgress, setHoverProgress] = useState<number | null>(null);
	const [layout, setLayout] = useState({ x: 0, y: 0, width: 0, height: 0 });
	const percent = hoverProgress! / (data?.durationSeconds ?? 1);

	return (
		<>
			<Slider
				progress={seek ?? progress}
				subtleProgress={buffer}
				max={data?.durationSeconds}
				startSeek={() => {
					player.pause();
				}}
				setProgress={setSeek}
				endSeek={() => {
					if (seek) seekPlayerTo(player, seek);
					setTimeout(() => player.play(), 10);
					setSeek(null);
				}}
				onHover={(progress, layout) => {
					setHoverProgress(progress);
					setLayout(layout);
				}}
				markers={chapters?.map((x) => x.startTime)}
				// @ts-expect-error dataSet is web only and not typed
				dataSet={{ tooltipId: "progress-scrubber" }}
			/>
			<Tooltip
				id={"progress-scrubber"}
				isOpen={hoverProgress !== null}
				// not a real fix, we should fix it upstream
				place={percent > 0.8 ? "top-end" : "top"}
				position={{
					x: layout.x + layout.width * percent,
					y: layout.y,
				}}
				render={() =>
					hoverProgress ? (
						<ScrubberTooltip
							seconds={hoverProgress}
							chapters={chapters}
							videoSlug={slug}
						/>
					) : null
				}
				opacity={1}
				style={{
					padding: 0,
					...(useResolveClassNames(
						cn("rounded bg-slate-200"),
					) as CSSProperties),
				}}
			/>
		</>
	);
};

export const ProgressText = ({ className, ...props }: TextProps) => {
	const progress = usePlayerState("currentTime");
	const [slug] = useQueryState<string>("slug", undefined!);
	const { data } = useFetch(Info.infoQuery(slug));

	return (
		<P className={cn("text-center", className)} {...props}>
			{toTimerString(progress, data?.durationSeconds)} :{" "}
			{toTimerString(data?.durationSeconds)}
		</P>
	);
};

export const toTimerString = (timer?: number, duration?: number) => {
	if (!duration) duration = timer;
	if (timer === undefined || !Number.isFinite(timer)) return "??:??";

	const h = Math.floor(timer / 3600);
	const min = Math.floor((timer / 60) % 60);
	const sec = Math.floor(timer % 60);
	const fmt = (n: number) => n.toString().padStart(2, "0");

	return h !== 0 || (duration && duration >= 3600)
		? `${fmt(h)}:${fmt(min)}:${fmt(sec)}`
		: `${fmt(min)}:${fmt(sec)}`;
};
