/*
 * Kyoo - A portable and vast media library solution.
 * Copyright (c) Kyoo.
 *
 * See AUTHORS.md and LICENSE file in the project root for full license information.
 *
 * Kyoo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * Kyoo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
 */

import type { Subtitle } from "@kyoo/models";
import { atom, useSetAtom } from "jotai";
import { useEffect } from "react";
import { Platform } from "react-native";
import { useRouter } from "solito/router";
import {
	durationAtom,
	fullscreenAtom,
	mutedAtom,
	playAtom,
	progressAtom,
	subtitleAtom,
	volumeAtom,
} from "./state";

type Action =
	| { type: "play" }
	| { type: "mute" }
	| { type: "fullscreen" }
	| { type: "seek"; value: number }
	| { type: "seekTo"; value: number }
	| { type: "seekPercent"; value: number }
	| { type: "volume"; value: number }
	| { type: "subtitle"; subtitles: Subtitle[]; fonts: string[] };

export const reducerAtom = atom(null, (get, set, action: Action) => {
	const duration = get(durationAtom);
	switch (action.type) {
		case "play":
			set(playAtom, !get(playAtom));
			break;
		case "mute":
			set(mutedAtom, !get(mutedAtom));
			break;
		case "fullscreen":
			set(fullscreenAtom, !get(fullscreenAtom));
			break;
		case "seek":
			if (duration)
				set(progressAtom, Math.max(0, Math.min(get(progressAtom) + action.value, duration)));
			break;
		case "seekTo":
			set(progressAtom, action.value);
			break;
		case "seekPercent":
			if (duration) set(progressAtom, (duration * action.value) / 100);
			break;
		case "volume":
			set(volumeAtom, Math.max(0, Math.min(get(volumeAtom) + action.value, 100)));
			break;
		case "subtitle": {
			const subtitle = get(subtitleAtom);
			const index = subtitle ? action.subtitles.findIndex((x) => x.index === subtitle.index) : -1;
			set(
				subtitleAtom,
				index === -1 ? null : action.subtitles[(index + 1) % action.subtitles.length],
			);
			break;
		}
	}
});

export const useVideoKeyboard = (
	subtitles?: Subtitle[],
	fonts?: string[],
	previousEpisode?: string,
	nextEpisode?: string,
) => {
	const reducer = useSetAtom(reducerAtom);
	const router = useRouter();

	useEffect(() => {
		if (Platform.OS !== "web") return;
		const handler = (event: KeyboardEvent) => {
			if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return;

			switch (event.key) {
				case " ":
				case "k":
				case "MediaPlay":
				case "MediaPause":
				case "MediaPlayPause":
					reducer({ type: "play" });
					break;

				case "m":
					reducer({ type: "mute" });
					break;

				case "ArrowLeft":
					reducer({ type: "seek", value: -5 });
					break;
				case "ArrowRight":
					reducer({ type: "seek", value: +5 });
					break;

				case "j":
					reducer({ type: "seek", value: -10 });
					break;
				case "l":
					reducer({ type: "seek", value: +10 });
					break;

				case "ArrowUp":
					reducer({ type: "volume", value: +5 });
					break;
				case "ArrowDown":
					reducer({ type: "volume", value: -5 });
					break;

				case "f":
					reducer({ type: "fullscreen" });
					break;

				case "v":
				case "c":
					if (!subtitles || !fonts) return;
					reducer({ type: "subtitle", subtitles, fonts });
					break;

				case "n":
				case "N":
					if (nextEpisode) router.push(nextEpisode);
					break;

				case "p":
				case "P":
					if (previousEpisode) router.push(previousEpisode);
					break;

				default:
					break;
			}
			switch (event.code) {
				case "Digit0":
					reducer({ type: "seekPercent", value: 0 });
					break;
				case "Digit1":
					reducer({ type: "seekPercent", value: 10 });
					break;
				case "Digit2":
					reducer({ type: "seekPercent", value: 20 });
					break;
				case "Digit3":
					reducer({ type: "seekPercent", value: 30 });
					break;
				case "Digit4":
					reducer({ type: "seekPercent", value: 40 });
					break;
				case "Digit5":
					reducer({ type: "seekPercent", value: 50 });
					break;
				case "Digit6":
					reducer({ type: "seekPercent", value: 60 });
					break;
				case "Digit7":
					reducer({ type: "seekPercent", value: 70 });
					break;
				case "Digit8":
					reducer({ type: "seekPercent", value: 80 });
					break;
				case "Digit9":
					reducer({ type: "seekPercent", value: 90 });
					break;
			}
		};

		document.addEventListener("keyup", handler);
		return () => document.removeEventListener("keyup", handler);
	}, [subtitles, fonts, nextEpisode, previousEpisode, router, reducer]);
};
