<script lang="ts">
import { onMount } from "svelte";
import EditWindow from "./edit_window/EditWindow.svelte";
import Toolbar from "./Toolbar.svelte";
import Breadcrumbs from "./Breadcrumbs.svelte";
import DetailsWindow from "./DetailsWindow.svelte";
import FilePreview from "./viewers/FilePreview.svelte";
import FSUploadWidget from "./upload_widget/FSUploadWidget.svelte";
import { global_navigator } from "./FSNavigator"
import { css_from_path } from "filesystem/edit_window/Branding";
import AffiliatePrompt from "user_home/AffiliatePrompt.svelte";
import { current_page_store } from "wrap/RouterStore";
import SearchBar from "./SearchBar.svelte";
import ErrorPage from "./ErrorPage.svelte";

let file_preview: FilePreview = $state()
let toolbar: Toolbar = $state()
let upload_widget: FSUploadWidget = $state()
let details_visible = $state(false)
let edit_window: EditWindow = $state()
let edit_visible = $state(false)
let details_window: DetailsWindow = $state()
let search_bar: SearchBar = $state()

const nav = global_navigator

onMount(() => {
	// There is a global navigation handler which captures link clicks and loads
	// the right svelte components. When a filesystem link is clicked this store
	// is updated. Catch it and use the filesystem navigator to navigate to the
	// right file
	const page_sub = current_page_store.subscribe(() => {
		console.debug("Caught page transition to", window.location.pathname, "calling navigator")
		nav.navigate(decodeURIComponent(window.location.pathname).replace(/^\/d/, ""), false)
	})

	// Subscribe to navigation updates. This function returns a deconstructor
	// which we can conveniently return from our mount function as well
	const nav_sub = nav.subscribe(nav => {
		if (!nav.initialized) {
			return
		}

		// Custom CSS rules for the whole viewer. The MainMenu applies its
		// styles to the <html> element. So we apply to the <body> element, our
		// styles take precedence since they're lower level, and we can clean it
		// up afterwards without overwriting global style
		document.body.style = css_from_path(nav.path)
	})
	return () => {
		page_sub()
		nav_sub()
		document.body.style = ""
	}
})

const keydown = (e: KeyboardEvent) => {
	if (e.ctrlKey || e.altKey || e.metaKey) {
		return // prevent custom shortcuts from interfering with system shortcuts
	} else if (
		(document.activeElement as any).type !== undefined &&
		(
			(document.activeElement as any).type === "text" ||
			(document.activeElement as any).type === "textarea"
		)
	) {
		return // Prevent shortcuts from interfering with input fields
	}

	let action_performed = true
	switch (e.key) {
		case "c":
			toolbar.copy_link()
			break;
		case "i":
			details_visible = !details_visible
			break;
		case "e":
			if (edit_visible) {
				edit_visible = false
			} else {
				edit_window.edit(nav.base, true, "file")
			}
			break;
		case "s":
			nav.base.download()
			break;
		case "r":
			nav.shuffle = !nav.shuffle
			break;
		case "/":
			search_bar.open()
			break;
		case "a":
		case "ArrowLeft":
			nav.open_sibling(-1)
			break;
		case "d":
		case "ArrowRight":
			nav.open_sibling(1)
			break;
		case " ": // Spacebar pauses / unpauses video and audio playback
			if (file_preview) {
				if (file_preview.toggle_playback()) {
					e.preventDefault()
					e.stopPropagation()
				}
			}
			break
		case "m": // M mutes / unmutes audio
			if (file_preview) {
				file_preview.toggle_mute()
			}
			break
		case "h":
			file_preview.seek(-20)
			break
		case "j":
			file_preview.seek(-5)
			break
		case "k":
			file_preview.seek(5)
			break
		case "l":
			file_preview.seek(20)
			break
		case ",":
			file_preview.seek(-0.04) // Roughly a single frame.. assuming 25fps
			break
		case ".":
			file_preview.seek(0.04)
			break
		default:
			action_performed = false
	}

	if (action_performed) {
		e.preventDefault()
	}
};
</script>

<svelte:window onkeydown={keydown} />

{#if $nav.navigation_error === ""}
<div class="filesystem">
	<Breadcrumbs nav={nav} edit_window={edit_window}/>

	<div class="file_preview">
		<FilePreview
			bind:this={file_preview}
			nav={nav}
			upload_widget={upload_widget}
			edit_window={edit_window}
			details_window={details_window}
			search_bar={search_bar}
		/>
	</div>

	<Toolbar
		bind:this={toolbar}
		nav={nav}
		bind:details_visible={details_visible}
		edit_window={edit_window}
		bind:edit_visible={edit_visible}
	/>
</div>

{:else}
	<ErrorPage nav={nav} />
{/if}

<SearchBar bind:this={search_bar} nav={nav}/>

<DetailsWindow nav={nav} bind:this={details_window} bind:visible={details_visible} />

<EditWindow nav={nav} bind:this={edit_window} bind:visible={edit_visible} />

<!-- This one is included at the highest level so uploads can keep running
	even when the user navigates to a different directory -->
<FSUploadWidget nav={nav} bind:this={upload_widget} />

<AffiliatePrompt/>

<style>
:global(*) {
	transition: background-color 0.2s,
		border 0.2s,
		border-top 0.2s,
		border-right 0.2s,
		border-bottom 0.2s,
		border-left 0.2s,
		color 0.2s;
}

/* Viewer container */
.filesystem {
	display: flex;
	flex-direction: column;
	flex: 1 1 auto; /* auto grow */
}

.file_preview {
	flex: 1 1 auto;
	overflow: auto;
}
</style>
