/**
 * Temporal Foundation — Node 26 native date/time helpers
 *
 * Purpose: provide one native Temporal surface for schedules, leases, and
 * background work now that Node 26 is the runtime baseline.
 *
 * Consumer: schedule, journal, lease, and background task surfaces.
 */

function requireTemporal() {
	if (typeof globalThis.Temporal !== "object" || globalThis.Temporal === null) {
		throw new Error("SF requires Node 26 native Temporal support");
	}
	return globalThis.Temporal;
}

/**
 * Check if native Temporal is available.
 *
 * Purpose: let startup diagnostics fail clearly when SF is launched on a
 * runtime older than the Node 26 baseline.
 *
 * Consumer: doctor/startup checks and Temporal tests.
 */
export function hasNativeTemporal() {
	return (
		typeof globalThis.Temporal === "object" && globalThis.Temporal !== null
	);
}

/**
 * Return the native Temporal namespace.
 *
 * Purpose: keep callers on the platform implementation instead of local
 * compatibility shims.
 *
 * Consumer: modules that need Temporal constructors directly.
 */
export function getTemporal() {
	return requireTemporal();
}

/**
 * Create a Temporal.Instant from an ISO string.
 *
 * Purpose: exact event timestamps with stable ordering.
 *
 * Consumer: journals, leases, and scheduler records.
 */
export function instantFromISO(isoString) {
	return requireTemporal().Instant.from(isoString);
}

/**
 * Get the current instant.
 *
 * Purpose: use a native Temporal clock value for runtime records.
 *
 * Consumer: schedule and lease code that needs an exact timestamp.
 */
export function instantNow() {
	return requireTemporal().Now.instant();
}

/**
 * Create a Temporal.Duration from an object.
 *
 * Purpose: typed durations for leases, budgets, retry delays.
 *
 * Consumer: retry, timeout, and reminder scheduling code.
 */
export function durationFromObject({
	years = 0,
	months = 0,
	weeks = 0,
	days = 0,
	hours = 0,
	minutes = 0,
	seconds = 0,
	milliseconds = 0,
} = {}) {
	return requireTemporal().Duration.from({
		years,
		months,
		weeks,
		days,
		hours,
		minutes,
		seconds,
		milliseconds,
	});
}

/**
 * Create a Temporal.PlainDate from an ISO string.
 *
 * Purpose: calendar dates for daily reports and milestone reviews.
 *
 * Consumer: schedule and reporting code that needs date-only semantics.
 */
export function plainDateFromISO(isoString) {
	return requireTemporal().PlainDate.from(isoString);
}

/**
 * Create a Temporal.ZonedDateTime from an ISO string and time zone.
 *
 * Purpose: local-time reminders that survive DST changes.
 *
 * Consumer: scheduled reminders and audit views rendered in local time.
 */
export function zonedDateTimeFromISO(isoString, timeZone = "UTC") {
	const Temporal = requireTemporal();
	return Temporal.Instant.from(isoString).toZonedDateTimeISO(timeZone);
}

/**
 * Serialize a Temporal value to a stable JSON-friendly object.
 *
 * Purpose: store semantic type plus ISO string so consumers know how to parse.
 *
 * Consumer: DB records and generated projections that persist Temporal values.
 */
export function serializeTemporal(value) {
	if (!value) return null;
	const Temporal = requireTemporal();
	if (value instanceof Temporal.Instant) {
		return { type: "Instant", iso: value.toString() };
	}
	if (value instanceof Temporal.Duration) {
		return { type: "Duration", iso: value.toString() };
	}
	if (value instanceof Temporal.PlainDate) {
		return { type: "PlainDate", iso: value.toString() };
	}
	if (value instanceof Temporal.ZonedDateTime) {
		return {
			type: "ZonedDateTime",
			iso: value.toString(),
			timeZone: value.timeZoneId,
		};
	}
	throw new TypeError(
		`Unsupported Temporal value: ${Object.prototype.toString.call(value)}`,
	);
}

/**
 * Deserialize a serialized Temporal value.
 *
 * Purpose: reconstruct the same native Temporal type that was stored.
 *
 * Consumer: schedule and UOK state loaders.
 */
export function deserializeTemporal(serialized) {
	if (!serialized || typeof serialized !== "object") return null;
	const Temporal = requireTemporal();
	switch (serialized.type) {
		case "Instant":
			return Temporal.Instant.from(serialized.iso);
		case "Duration":
			return Temporal.Duration.from(serialized.iso);
		case "PlainDate":
			return Temporal.PlainDate.from(serialized.iso);
		case "ZonedDateTime":
			return Temporal.ZonedDateTime.from(serialized.iso);
		default:
			throw new TypeError(`Unknown Temporal type: ${serialized.type}`);
	}
}

/**
 * Validate that a schedule/lease record has correct Temporal serialization.
 *
 * Purpose: reject ambiguous Date-like records before they enter durable state.
 *
 * Consumer: schedule and UOK record validation.
 */
export function validateTemporalRecord(record) {
	const errors = [];
	const validTypes = ["Instant", "Duration", "PlainDate", "ZonedDateTime"];
	for (const [key, value] of Object.entries(record)) {
		if (value && typeof value === "object" && value.type) {
			if (!validTypes.includes(value.type)) {
				errors.push(`Field "${key}" has unknown Temporal type: ${value.type}`);
			}
			if (validTypes.includes(value.type) && !value.iso) {
				errors.push(`Field "${key}" is missing ISO string`);
			}
		}
	}
	return { valid: errors.length === 0, errors };
}
