import * as stylex from "@stylexjs/stylex";
import { memo } from "react";
import { interaction } from "./mixins";
import { size } from "./tokens.stylex";

export interface RefreshSpinnerProps {
	size: "small" | "medium";
	status: RefreshSpinnerStatus;
	pullPosition?: number;

	style?: stylex.StyleXStyles<{
		zIndex?: number;
	}>;
}

export type RefreshSpinnerStatus = "idle" | "pulling" | "refreshing" | "done";

const spin = stylex.keyframes({
	from: {
		rotate: "0deg",
	},
	to: {
		rotate: "360deg",
	},
});

const throb = stylex.keyframes({
	from: {
		opacity: 0.1,
	},
	to: {
		opacity: 0.5,
	},
});

const styles = stylex.create({
	svg: {
		fill: "currentColor",
		opacity: 0.5,
	},

	idle: {
		animationName: throb,
		animationDuration: "1s",
		animationTimingFunction: "ease-in-out",
		animationIterationCount: "infinite",
		animationDirection: "alternate",
	},
	pulling: (progressDegree) => ({
		maskImage: `conic-gradient(from ${progressDegree}deg, #fff0, #ffff)`,
	}),
	refreshing: {
		animationName: spin,
		animationDuration: "3s",
		animationTimingFunction: "linear",
		animationIterationCount: "infinite",
	},
	done: {
		// We're setting the class instantly and don't remember the previous state
		// This means that the icon may be spinning before
		// we cannot retain its position, so it will jump back to the initial rotation. This would be visible if we'd animate the opacity.
		// transition: `opacity ${duration.slow}`,
		visibility: "hidden",
	},
});

const sizes = stylex.create({
	small: {
		width: size.px4,
		height: size.px4,
		maxWidth: size.px4,
		maxHeight: size.px4,
	},
	medium: {
		width: size.px8,
		height: size.px8,
		maxWidth: size.px8,
		maxHeight: size.px8,
	},
});

export default memo(function RefreshSpinner({
	size,
	status,
	pullPosition,
	style,
}: RefreshSpinnerProps) {
	return (
		// biome-ignore lint/a11y/noSvgWithoutTitle: it's a spinner, it doesn't need a title
		<svg
			xmlns="http://www.w3.org/2000/svg"
			width="24"
			height="24"
			viewBox="0 0 1024 1024"
			{...stylex.props(
				interaction.inert,
				styles.svg,
				sizes[size],
				status === "pulling"
					? styles.pulling(pullPosition)
					: styles[status],
				style,
			)}
		>
			<path d="M512 64a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V96a32 32 0 0 1 32-32zm0 640a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V736a32 32 0 0 1 32-32zm448-192a32 32 0 0 1-32 32H736a32 32 0 1 1 0-64h192a32 32 0 0 1 32 32zm-640 0a32 32 0 0 1-32 32H96a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32zM195.2 195.2a32 32 0 0 1 45.2 0l136 135.8a32 32 0 0 1-45.3 45.3L195.2 240.4a32 32 0 0 1 0-45.2zm452.5 452.5a32 32 0 0 1 45.3 0l135.8 135.9a32 32 0 0 1-45.2 45.2L647.7 693a32 32 0 0 1 0-45.3zm181.1-452.4a32 32 0 0 1 0 45.1L693 376.4a32 32 0 0 1-45.3-45.3l135.9-135.8a32 32 0 0 1 45.2 0zM376.3 647.7a32 32 0 0 1 0 45.3L240.4 828.8a32 32 0 0 1-45.2-45.2L331 647.7a32 32 0 0 1 45.3 0z" />
		</svg>
	);
});
