import type { ReactElement } from "react";
import { type PossibleDate, requireDate } from "../../util/date.js";
import { formatAgo, formatUntil, formatWhen, getSecondsAgo } from "../../util/duration.js";
import { formatDateTime } from "../../util/format.js";
import type { AnyCaller } from "../../util/function.js";
import type { OptionalChildProps } from "../util/props.js";

const _OPTIONS: Intl.NumberFormatOptions = { unitDisplay: "narrow" };

function _getWhen(
	formatter: typeof formatWhen,
	{ target: possibleTarget, current: possibleCurrent = "now", full = false, children }: WhenProps,
	caller: AnyCaller,
): ReactElement {
	const target = requireDate(possibleTarget, caller);
	const current = requireDate(possibleCurrent, caller);
	const title = possibleCurrent === "now" ? formatDateTime(target) : `${formatDateTime(target)} to ${formatDateTime(current)}`;
	const formatted = children ?? (full ? `${title} (${formatter(target, current, _OPTIONS)})` : formatter(target, current, _OPTIONS));
	return (
		<time dateTime={possibleCurrent === "now" ? target.toISOString() : `PT${getSecondsAgo(target, current)}S`} title={title}>
			{formatted}
		</time>
	);
}

export interface WhenProps extends OptionalChildProps {
	target: PossibleDate | undefined;
	current?: PossibleDate | undefined;
	full?: boolean | undefined;
}

/** Show a string like `in 6d` or `3w ago` wrapped with a `<time>` element providing the machine-readable format of the same date. */
export function When(props: WhenProps): ReactElement {
	return _getWhen(formatWhen, props, When);
}

export interface AgoProps extends WhenProps {}

/** Show a string like `6d` or `3w` wrapped with a `<time>` element providing the machine-readable format of the same date. */
export function Ago(props: AgoProps): ReactElement {
	return _getWhen(formatAgo, props, Ago);
}

export interface UntilProps extends WhenProps {}

/** Show a string like `6d` or `3w` wrapped with a `<time>` element providing the machine-readable format of the same date. */
export function Until(props: UntilProps): ReactElement {
	return _getWhen(formatUntil, props, Until);
}
