import React from "react";
import { AtProtoRecord } from "../core/AtProtoRecord";
import { CurrentlyPlayingRenderer } from "../renderers/CurrentlyPlayingRenderer";
import { useDidResolution } from "../hooks/useDidResolution";
import type { TealActorStatusRecord } from "../types/teal";

/**
 * Props for rendering teal.fm currently playing status.
 */
export interface CurrentlyPlayingProps {
	/** DID of the user whose currently playing status to display. */
	did: string;
	/** Record key within the `fm.teal.alpha.actor.status` collection (usually "self"). */
	rkey?: string;
	/** Prefetched teal.fm status record. When provided, skips fetching from the network. */
	record?: TealActorStatusRecord;
	/** Optional renderer override for custom presentation. */
	renderer?: React.ComponentType<CurrentlyPlayingRendererInjectedProps>;
	/** Fallback node displayed before loading begins. */
	fallback?: React.ReactNode;
	/** Indicator node shown while data is loading. */
	loadingIndicator?: React.ReactNode;
	/** Preferred color scheme for theming. */
	colorScheme?: "light" | "dark" | "system";
	/** Auto-refresh music data and album art. When true, refreshes every 15 seconds. Defaults to true. */
	autoRefresh?: boolean;
	/** Refresh interval in milliseconds. Defaults to 15000 (15 seconds). Only used when autoRefresh is true. */
	refreshInterval?: number;
}

/**
 * Values injected into custom currently playing renderer implementations.
 */
export type CurrentlyPlayingRendererInjectedProps = {
	/** Loaded teal.fm status record value. */
	record: TealActorStatusRecord;
	/** Indicates whether the record is currently loading. */
	loading: boolean;
	/** Fetch error, if any. */
	error?: Error;
	/** Preferred color scheme for downstream components. */
	colorScheme?: "light" | "dark" | "system";
	/** DID associated with the record. */
	did: string;
	/** Record key for the status. */
	rkey: string;
	/** Label to display. */
	label?: string;
	/** Handle to display in not listening state */
	handle?: string;
};

/** NSID for teal.fm actor status records. */
export const CURRENTLY_PLAYING_COLLECTION = "fm.teal.alpha.actor.status";

/**
 * Compares two teal.fm status records to determine if the track has changed.
 * Used to prevent unnecessary re-renders during auto-refresh when the same track is still playing.
 */
const compareTealRecords = (
	prev: TealActorStatusRecord | undefined,
	next: TealActorStatusRecord | undefined
): boolean => {
	if (!prev || !next) return prev === next;
	
	const prevTrack = prev.item.trackName;
	const nextTrack = next.item.trackName;
	const prevArtist = prev.item.artists[0]?.artistName;
	const nextArtist = next.item.artists[0]?.artistName;
	
	return prevTrack === nextTrack && prevArtist === nextArtist;
};

/**
 * Displays the currently playing track from teal.fm with auto-refresh.
 *
 * @param did - DID whose currently playing status should be fetched.
 * @param rkey - Record key within the teal.fm status collection (defaults to "self").
 * @param renderer - Optional component override that will receive injected props.
 * @param fallback - Node rendered before the first load begins.
 * @param loadingIndicator - Node rendered while the status is loading.
 * @param colorScheme - Preferred color scheme for theming the renderer.
 * @param autoRefresh - When true (default), refreshes the record every 15 seconds (or custom interval).
 * @param refreshInterval - Custom refresh interval in milliseconds. Defaults to 15000 (15 seconds).
 * @returns A JSX subtree representing the currently playing track with loading states handled.
 */
export const CurrentlyPlaying: React.FC<CurrentlyPlayingProps> = React.memo(({
	did,
	rkey = "self",
	record,
	renderer,
	fallback,
	loadingIndicator,
	colorScheme,
	autoRefresh = true,
	refreshInterval = 15000,
}) => {
	// Resolve handle from DID
	const { handle } = useDidResolution(did);

	const Comp: React.ComponentType<CurrentlyPlayingRendererInjectedProps> =
		renderer ?? ((props) => <CurrentlyPlayingRenderer {...props} />);
	const Wrapped: React.FC<{
		record: TealActorStatusRecord;
		loading: boolean;
		error?: Error;
	}> = (props) => (
		<Comp
			{...props}
			colorScheme={colorScheme}
			did={did}
			rkey={rkey}
			label="CURRENTLY PLAYING"
			handle={handle}
		/>
	);

	if (record !== undefined) {
		return (
			<AtProtoRecord<TealActorStatusRecord>
				record={record}
				renderer={Wrapped}
				fallback={fallback}
				loadingIndicator={loadingIndicator}
			/>
		);
	}

	return (
		<AtProtoRecord<TealActorStatusRecord>
			did={did}
			collection={CURRENTLY_PLAYING_COLLECTION}
			rkey={rkey}
			renderer={Wrapped}
			fallback={fallback}
			loadingIndicator={loadingIndicator}
			refreshInterval={autoRefresh ? refreshInterval : undefined}
			compareRecords={compareTealRecords}
		/>
	);
});

export default CurrentlyPlaying;
