import React from "react";
import { Api, Jellyfin } from "@jellyfin/sdk";
import { getSearchApi } from "@jellyfin/sdk/lib/utils/api/search-api";
import { BaseItemKind } from "@jellyfin/sdk/lib/generated-client/models";
import SettingsModal from "./settings";

let hijackActive = false;

export const jellyfin = new Jellyfin({
	clientInfo: {
		name: "Spicetify",
		version: "1.0.0",
	},
	deviceInfo: {
		name: "Spotify",
		id: "spotify", // TODO: should be unique?
	},
});

export let jellyfinApi: Api | undefined;
export const setJellyfinApi = (api: Api) => {
	jellyfinApi = api;
};
export let jellyfinUser: string | undefined;
export const setJellyfinUser = (id: string) => {
	jellyfinUser = id;
};

async function main() {
	while (!Spicetify.showNotification) {
		await new Promise((resolve) => setTimeout(resolve, 100));
	}

	const audio = new Audio();

	// Topbar button for settings
	new Spicetify.Topbar.Button("Jellyfin", "podcasts", () => {
		Spicetify.PopupModal.display({
			title: "Jellyfin",
			content: React.createElement(SettingsModal) as unknown as Element,
			isLarge: false,
		});
	});

	// Search Jellyfin for song and play that instead if found
	Spicetify.Player.addEventListener("songchange", async (event) => {
		if (!jellyfinApi) return;
		if (!event) return;

		const results = await getSearchApi(jellyfinApi).getSearchHints({
			searchTerm: event.data.item.name,
			includeItemTypes: [BaseItemKind.Audio],
			limit: 1,
		});

		const item = results.data.SearchHints?.[0];
		if (!item?.Id) {
			const oldVolume = Spicetify.Player.getVolume();
			hijackActive = false;
			Spicetify.Platform.PlaybackAPI.setVolume(oldVolume);
			return;
		}

		Spicetify.showNotification("Playing on Jellyfin");

		const oldVolume = Spicetify.Player.getVolume();
		Spicetify.Platform.PlaybackAPI.setVolume(0); // Set Spotify audio volume to 0

		hijackActive = true;
		audio.src = `${jellyfinApi.basePath}/Audio/${item.Id}/universal?api_key=${jellyfinApi.accessToken}&UserId=${jellyfinUser}&Container=opus,webm|opus,mp3,aac,m4a|aac,m4a|alac,m4b|aac,flac,webma,webm|webma,wav,ogg&TranscodingContainer=ts&TranscodingProtocol=hls&AudioCodec=aac&MaxStreamingBitrate=140000000&EnableRedirection=true`;
		await audio.play();

		Spicetify.Platform.PlaybackAPI.setVolume(oldVolume); // Set Jellyfin audio volume to the actual volume
	});

	// Play/pause Jellyfin audio
	Spicetify.Player.addEventListener("onplaypause", async (event) => {
		if (!hijackActive) return;

		if (event?.data.isPaused) {
			audio.pause();
		} else {
			await audio.play();
		}
	});

	// Seeking support
	let oldTime = 0;
	Spicetify.Player.addEventListener("onprogress", async (event) => {
		if (!hijackActive) return;
		if (!event) return;

		// onprogress polls every 100ms, small time difference means normal playback
		const timeDiff = Math.abs(event.data - oldTime);
		if (Math.abs(timeDiff - 100) < 100) {
			// Allow 100ms tolerance
			oldTime = event.data;
			return;
		}

		audio.currentTime = event.data / 1000;
		oldTime = event.data;
	});

	// Change volume of Jellyfin audio instead of Spotify audio
	const playback = Spicetify.Platform.PlaybackAPI;
	playback.setVolume = new Proxy(playback.setVolume, {
		apply(target, thisArg, args) {
			if (hijackActive) {
				audio.volume = args[0];
				return;
			} else {
				return Reflect.apply(target, thisArg, args);
			}
		},
	});
}

main();
