<script lang="ts">
	import {
		ArrowBigLeft,
		ArrowBigRight,
		ChevronDown,
		Keyboard,
		Power,
		PowerOff,
		Presentation,
		SquareTerminal,
		TextAlignStart,
		TrafficCone,
		Globe
	} from 'lucide-svelte';
	import Button from '$lib/components/Button.svelte';
	import PopUp from '$lib/components/PopUp.svelte';
	import type { PopupContent } from '$lib/ts/types';
	import KeyInput from './KeyInput.svelte';
	import {
		send_keyboard_input,
		show_blackscreen,
		shutdown,
		startup,
		open_website
	} from '$lib/ts/api_handler';
	import {
		get_display_by_id,
		run_on_all_selected_displays,
		selected_online_display_ids
	} from '$lib/ts/stores/displays';
	import { selected_display_ids } from '$lib/ts/stores/select';
	import TipTapInput from './TipTapInput.svelte';
	import { db } from '$lib/ts/database';
	import { liveQuery, type Observable } from 'dexie';
	import TextInput from '$lib/components/TextInput.svelte';
	import { add_to_keyboard_queue } from '$lib/ts/utils';
	import { onMount } from 'svelte';

	let all_display_states: Observable<'on' | 'off' | 'mixed'> | undefined = $state();
	$effect(() => {
		const ids = $selected_display_ids;
		all_display_states = liveQuery(() => all_state(ids));
	});

	let popup_content: PopupContent = $state({
		open: false,
		snippet: null,
		title: ''
	});

	let current_text = $state('');

	const key_pressed = $state({
		ArrowRight: false,
		ArrowLeft: false
	});

	function popup_close_function() {
		popup_content.open = false;
	}

	const show_send_keys_popup = () => {
		popup_content = {
			open: true,
			snippet: send_keys_popup,
			title: 'Tastatur-Eingaben Senden',
			title_icon: Keyboard,
			window_class: 'h-full'
		};
	};

	const show_text_popup = () => {
		popup_content = {
			open: true,
			snippet: text_popup,
			title: 'Text Anzeigen',
			title_icon: TextAlignStart,
			window_class: 'size-full'
		};
	};

	const show_website_popup = () => {
		popup_content = {
			open: true,
			snippet: website_popup,
			title: 'Webseite Anzeigen',
			window_class: 'w-xl',
			title_icon: Globe
		};
	};

	async function all_state(selected_display_ids: string[]): Promise<'on' | 'off' | 'mixed'> {
		const selected_displays = await Promise.all(
			selected_display_ids.map(async (id) => await get_display_by_id(id))
		);
		const selected_display_states = selected_displays.map((display) => display?.status ?? '');
		if (selected_display_states.every((state) => state === 'app_online')) {
			return 'on';
		} else if (selected_display_states.every((state) => state !== 'app_online')) {
			return 'off';
		} else {
			return 'mixed';
		}
	}

	async function ask_shutdown() {
		popup_content = {
			open: true,
			snippet: ask_shutdown_popup,
			title: 'Bildschirm Herunterfahren',
			title_icon: PowerOff
		};
	}

	async function shutdown_action() {
		popup_content.open = false;
		await run_on_all_selected_displays(async (d) => {
			if (await shutdown(d.ip)) {
				db.displays.update(d.id, {
					status: 'app_offline',
					preview: { currently_updating: false, url: null }
				});
			}
		}, false);
	}

	async function startup_action() {
		await run_on_all_selected_displays(
			async (d) => {
				if (!d.mac) return;
				startup(d.mac); // no await here because we want to be fast
				db.displays.update(d.id, { status: 'app_offline' });
			},
			false,
			$selected_display_ids
		);
	}

	async function send_single_key_press(key: string, action: 'press' | 'release') {
		await run_on_all_selected_displays((d) => send_keyboard_input(d.ip, [{ key, action }]));
	}
	let website_url = $state('');
	let website_url_valid = $state(false);

	function validate_website_url(url: string): [boolean, string] {
		if (url === '') return [true, ''];
		const regex = /^https?:\/\/[\w-]+(\.[\w-]+)+([\w\-._~:/?#[\]@!$&'()*+,;=.])*/;
		if (regex.test(url)) {
			return [true, ''];
		}
		return [false, 'Ungültige URL'];
	}

	async function send_website() {
		popup_content.open = false;
		await run_on_all_selected_displays((d) => open_website(d.ip, website_url));
	}

	function has_open_popup(): boolean {
		return document.querySelector('.popup') !== null;
	}

	function handle_key(
		event: KeyboardEvent,
		key: 'ArrowRight' | 'ArrowLeft',
		action: 'press' | 'release'
	) {
		if (event.key === key) {
			const current_press_state: boolean = key_pressed[key];
			if (
				(action === 'press' && (current_press_state === true || has_open_popup())) ||
				(action === 'release' && current_press_state === false)
			)
				return;

			key_pressed[key] = !current_press_state;
			add_to_keyboard_queue(async () => {
				await run_on_all_selected_displays(
					(d) => send_keyboard_input(d.ip, [{ key, action }]),
					true
				);
			});
		}
	}

	function add_remove_event_listeners(
		add_remove_function: (type: string, listener: (e: KeyboardEvent) => void) => void
	) {
		const actions = {
			keydown: 'press',
			keyup: 'release'
		} as const;
		const keys = ['ArrowRight', 'ArrowLeft'] as const;

		for (const [action_type, action_value] of Object.entries(actions)) {
			for (const key of keys) {
				add_remove_function(action_type, (e: KeyboardEvent) => handle_key(e, key, action_value));
			}
		}
	}

	onMount(() => {
		add_remove_event_listeners(window.addEventListener);
		return () => {
			add_remove_event_listeners(window.removeEventListener);
		};
	});
</script>

{#snippet website_popup()}
	<div class="flex flex-col gap-2">
		<TextInput
			title="URL (mit http:// oder https://)"
			placeholder="https://example.com"
			bind:current_value={website_url}
			bind:current_valid={website_url_valid}
			is_valid_function={validate_website_url}
			enter_mode="submit"
			enter_function={send_website}
		/>
		<div class="flex flex-row justify-end gap-2">
			<Button className="button space font-bold" click_function={popup_close_function}>
				Abbrechen
			</Button>
			<Button
				click_function={send_website}
				disabled={!website_url_valid || website_url === ''}
				className="button success space">Anzeigen</Button
			>
		</div>
	</div>
{/snippet}

{#snippet ask_shutdown_popup()}
	<p>Bist du sicher, dass du alle ausgewählten Displays herunterfahren möchtest?</p>

	<div class="flex flex-row justify-end gap-2">
		<Button className="button space font-bold" click_function={() => (popup_content.open = false)}>
			Abbrechen
		</Button>
		<Button click_function={shutdown_action} className="button error space">Herunterfahren</Button>
	</div>
{/snippet}

{#snippet send_keys_popup()}
	<KeyInput {popup_close_function} />
{/snippet}

{#snippet text_popup()}
	<TipTapInput bind:text={current_text} />
{/snippet}

<div class="grid grid-rows-[2.5rem_auto] bg-stone-800 rounded-2xl min-w-0">
	<div class="text-xl font-bold pl-3 content-center bg-stone-700 rounded-t-2xl truncate min-w-0">
		Bildschirme Steuern
	</div>
	<div class="relative flex flex-col gap-2 p-2 overflow-auto">
		<div class="flex flex-row justify-between gap-2">
			<div class="flex flex-col gap-2">
				<div class="flex flex-row gap-2 w-75 justify-normal">
					<button
						title="Vorherige Folie (Pfeil nach Links) [gedrückt halten möglich]"
						class="px-9 {key_pressed.ArrowLeft
							? 'bg-stone-500'
							: 'bg-stone-700'} {$selected_online_display_ids.length === 0
							? 'text-stone-500 cursor-not-allowed'
							: 'hover:bg-stone-600 active:bg-stone-500 cursor-pointer'} py-2 rounded-xl flex justify-center items-center transition-colors duration-200"
						disabled={$selected_online_display_ids.length === 0 || key_pressed.ArrowLeft}
						onmousedown={() => {
							add_to_keyboard_queue(async () => await send_single_key_press('ArrowLeft', 'press'));
						}}
						onmouseup={() => {
							add_to_keyboard_queue(
								async () => await send_single_key_press('ArrowLeft', 'release')
							);
						}}
					>
						<ArrowBigLeft />
					</button>

					<button
						title="Nächste Folie (Pfeil nach Rechts) [gedrückt halten möglich]"
						class="px-9 {key_pressed.ArrowRight
							? 'bg-stone-500 cursor-not-allowed'
							: `bg-stone-700 ${
									$selected_online_display_ids.length === 0
										? 'text-stone-500 cursor-not-allowed'
										: 'hover:bg-stone-600 active:bg-stone-500 cursor-pointer'
								}`}  py-2 rounded-xl flex justify-center items-center transition-colors duration-200"
						disabled={$selected_online_display_ids.length === 0 || key_pressed.ArrowRight}
						onmousedown={() => {
							add_to_keyboard_queue(async () => await send_single_key_press('ArrowRight', 'press'));
						}}
						onmouseup={() => {
							add_to_keyboard_queue(
								async () => await send_single_key_press('ArrowRight', 'release')
							);
						}}
					>
						<ArrowBigRight />
					</button>
				</div>

				<Button
					className="px-3 flex gap-3 w-75 justify-normal"
					click_function={show_text_popup}
					disabled={$selected_online_display_ids.length === 0}
					><TextAlignStart /> Text Anzeigen</Button
				>

				<Button
					className="px-3 flex gap-3 w-75 justify-normal"
					disabled={$selected_online_display_ids.length === 0}
					click_function={show_website_popup}><Globe /> Webseite Anzeigen</Button
				>

				<Button
					className="px-3 flex gap-3 w-75 justify-normal"
					disabled={$selected_online_display_ids.length === 0}
					click_function={async () => {
						await run_on_all_selected_displays((d) => show_blackscreen(d.ip));
					}}><Presentation />Blackout</Button
				>

				<div class="flex flex-row justify-normal">
					<Button className="rounded-r-none pl-3 flex gap-3 grow w-65 justify-normal" disabled>
						<TrafficCone /> Fallback-Bild Anzeigen
					</Button>
					<Button className="rounded-l-none flex grow-0 w-10" disabled><ChevronDown /></Button>
				</div>

				<Button
					className="px-3 flex gap-3 w-75 justify-normal"
					disabled={$selected_online_display_ids.length === 0}
					click_function={show_send_keys_popup}><Keyboard /> Tastatur-Eingaben Senden</Button
				>
			</div>
			<div class="flex flex-col gap-2 justify-between">
				<div class="flex flex-col gap-2">
					<Button
						className="px-3 flex gap-3 w-full xl:w-75 justify-normal"
						disabled={$all_display_states === 'on' || $selected_display_ids.length === 0}
						click_function={startup_action}
					>
						<Power /> Bildschirm Hochfahren
					</Button>

					<Button
						className="px-3 flex gap-3 w-full xl:w-75 justify-normal"
						disabled={$all_display_states === 'off' || $selected_online_display_ids.length === 0}
						click_function={ask_shutdown}
					>
						<PowerOff /> Bildschirm Herunterfahren</Button
					>
				</div>
				<Button className="px-3 flex gap-3 w-full xl:w-75 justify-normal" disabled>
					<SquareTerminal />
					Shell-Befehl Ausführen
				</Button>
			</div>
		</div>
		<PopUp
			content={popup_content}
			close_function={popup_close_function}
			className="rounded-b-2xl"
			snippet_container_class="size-full"
		/>
	</div>
</div>
