<script lang="ts">
	import { onDestroy, onMount } from "svelte"
	import { goto } from "$app/navigation"
	import ThemeToggle from "./ThemeToggle.svelte"
	import Sidebar from "./Sidebar.svelte"
	import NoteEditor from "./NoteEditor.svelte"
	import SettingsModal from "./SettingsModal.svelte"
	import {
		apiClient,
		currentUser,
		currentFullNote,
		availableNotes,
		versionHistory,
		cError,
		type FullNote,
		cSuccess
	} from "$lib/client"
	import ToggleSidebar from "$lib/icons/ToggleSidebar.svelte"
	import VersionArrow from "$lib/icons/VersionArrow.svelte"
	import Close from "$lib/icons/Close.svelte"
	import { ERR_NOTIFICATION_DUR, SUC_NOTIFICATION_DUR } from "$lib/const"

	// State
	let isComponentReady = false
	let sidebarOpen = window.innerWidth > 768
	let showSettings = false
	let showVersionsDropdown = false
	let isEditing = false
	let errorTimeout: ReturnType<typeof setTimeout> | null = null
	let successTimeout: ReturnType<typeof setTimeout> | null = null

	onMount(async (): Promise<any> => {
		// The following fetch attempts to refresh any expired tokens automatically
		await apiClient.getCurrentUser()

		// If still no current user after the fetch attempt, redirect to login
		if (!$currentUser) {
			console.log("[VIEW] No user data found, routing to login page")
			goto("/login")
			return
		}

		await loadNotes()

		// Default to sidebar closed on mobile
		const handleResize = () => {
			if (window.innerWidth < 768 && sidebarOpen) {
				sidebarOpen = false
			}
		}

		handleResize()

		// Keep listening to browser's resize events
		window.addEventListener("resize", handleResize)

		isComponentReady = true

		return () => {
			window.removeEventListener("resize", handleResize)
		}
	})

	const loadNotes = async () => {
		const notes = await apiClient.listNotes()

		if (notes) {
			availableNotes.set(notes)
		}
	}

	const toggleVersionDropdown = () => {
		showVersionsDropdown = !showVersionsDropdown
	}

	const toggleSidebar = () => {
		sidebarOpen = !sidebarOpen
	}

	const closeSidebar = () => {
		sidebarOpen = false
	}

	const toggleSettings = () => {
		showSettings = !showSettings
	}

	const createNewNote = async () => {
		const newNote = await apiClient.createNote()

		if (newNote) {
			// Refresh notes list
			await loadNotes()

			// Get the full note details of the newly created note
			// (we need to find the ID from the updated `availableNotes`)
			if ($availableNotes && $availableNotes.length > 0) {
				const latestNote = $availableNotes[0] // Assuming the latest note is first
				await selectNote(latestNote.id, true)
			}

			isEditing = true // Open brand new notes in edit mode by default
		}
	}

	const isLatestVersion = (note: FullNote | null) => {
		if (!note) {
			return true
		}

		return note.isActiveVersion
	}

	const selectNote = async (noteID: string, fetchRemote: boolean) => {
		const note = await apiClient.getActiveFullNote(noteID, fetchRemote)

		if (note) {
			currentFullNote.set(note)
			isEditing = false
		}

		const history = await apiClient.getNoteHistory(noteID, fetchRemote)

		if (history) {
			versionHistory.set(history)
		}

		// MOBILE: Close sidebar when selecting a note from the list
		if (window.innerWidth < 768) {
			closeSidebar()
		}
	}

	const selectVersion = async (versionID: string) => {
		if ($currentFullNote) {
			const note = await apiClient.getFullVersion($currentFullNote.id, versionID)

			if (note) {
				currentFullNote.set(note)
				showVersionsDropdown = false
			}
		}
	}

	const toggleEditMode = () => {
		if (isLatestVersion($currentFullNote)) {
			isEditing = !isEditing
		} else {
			cError.set("Editing historical versions is prohibited.")
		}
	}

	const saveNote = async (title: string, content: string) => {
		if ($currentFullNote) {
			await apiClient.createVersion($currentFullNote.id, title, content)

			// Refresh the current note to get the latest version (+ assure that client and server are synced)
			await selectNote($currentFullNote.id, true)

			// Refresh the notes list to update any changes (ordering based on `updatedAt` field)
			await loadNotes()

			isEditing = false
		}
	}

	const deleteNote = async (noteID: string) => {
		await apiClient.deleteNote(noteID)

		// If we're deleting the currently active note, clear the current note
		if ($currentFullNote && $currentFullNote.id === noteID) {
			currentFullNote.set(null)
		}

		// Refresh the notes list due to updates being pushed to server
		await loadNotes()

		cSuccess.set("Note deleted successfully.")
	}

	const logout = async () => {
		await apiClient.logout()
	}

	const errorUnsubscribe = cError.subscribe((value) => {
		// Clear any existing timeout to avoid multiple timeouts
		if (errorTimeout) {
			clearTimeout(errorTimeout)
			errorTimeout = null
		}

		if (value) {
			errorTimeout = setTimeout(() => {
				cError.set(null)
			}, ERR_NOTIFICATION_DUR)
		}
	})

	const successUnsubscribe = cSuccess.subscribe((value) => {
		// Clear any existing timeout to avoid multiple timeouts
		if (successTimeout) {
			clearTimeout(successTimeout)
			successTimeout = null
		}

		if (value) {
			successTimeout = setTimeout(() => {
				cSuccess.set(null)
			}, SUC_NOTIFICATION_DUR)
		}
	})

	onDestroy(() => {
		errorUnsubscribe()
		successUnsubscribe()

		// Clear any pending timeouts
		if (errorTimeout) {
			clearTimeout(errorTimeout)
		}

		if (successTimeout) {
			clearTimeout(successTimeout)
		}
	})
</script>

{#if isComponentReady}
	<div class="main-layout-container">
		<!-- Error notification -->
		{#if $cError}
			<div class="main-info-popup">
				<div class="error">
					{$cError}
					<button class="main-info-popup-button" on:click={() => cError.set(null)}>
						<Close />
					</button>
				</div>
			</div>
		{/if}

		<!-- Success notification -->
		{#if $cSuccess}
			<div class="main-info-popup">
				<div class="success">
					{$cSuccess}
					<button class="main-info-popup-button" on:click={() => cSuccess.set(null)}>
						<Close />
					</button>
				</div>
			</div>
		{/if}

		<!-- Sidebar (2-way binding prop allows changing the same var. in either component) -->
		<Sidebar
			bind:sidebarOpen
			notes={$availableNotes || []}
			currentNote={$currentFullNote}
			{toggleSettings}
			{logout}
			{createNewNote}
			{selectNote}
			{deleteNote}
			on:close={closeSidebar}
		/>

		<!-- Main content area -->
		<div
			class="content-wrapper transition-all duration-300"
			class:md:-ml-64={!sidebarOpen}
			class:md:ml-0={sidebarOpen}
		>
			<!-- Top navbar -->
			<header class="main-header">
				<button
					on:click={toggleSidebar}
					class="btn-secondary rounded-full p-2"
					aria-label="Toggle sidebar"
				>
					<ToggleSidebar />
				</button>

				<div class="flex items-center space-x-4 pl-2">
					{#if $currentFullNote}
						<!-- Note edit/preview button (only shown for latest version) -->
						{#if isLatestVersion($currentFullNote)}
							<button on:click={toggleEditMode} class="btn-primary rounded-full">
								{isEditing ? "Preview" : "Edit"}
							</button>
						{:else}
							<button disabled class="btn-primary cursor-not-allowed rounded-full opacity-40">
								Edit
							</button>
						{/if}

						<!-- Version history dropdown menu -->
						<div class="relative">
							<button
								on:click={toggleVersionDropdown}
								class="btn-secondary flex items-center rounded-full"
							>
								<span>Versions</span>
								<VersionArrow />
							</button>

							{#if showVersionsDropdown && $versionHistory && $versionHistory.length > 0}
								<div class="versions-dropdown">
									{#each $versionHistory as version}
										<button
											on:click={() => selectVersion(version.versionID)}
											class="versions-dropdown-item {$currentFullNote.versionNumber ===
											version.versionNumber
												? 'versions-dropdown-item-active'
												: ''}"
										>
											<p class="versions-dropdown-item-text truncate font-bold">{version.title}</p>
											<span class="versions-dropdown-item-text"
												>{version.createdAt.toLocaleString()}</span
											>
											{#if version.isActive}<span
													class="versions-dropdown-item-text ml-2 opacity-70">(active)</span
												>{/if}
										</button>
									{/each}
								</div>
							{/if}
						</div>
					{/if}
				</div>

				<div class="flex items-center space-x-4 pl-2">
					<ThemeToggle />
				</div>
			</header>

			<!-- Note content area with fixed width -->
			<div class="note-content-fixed-width">
				<main class="main-content">
					{#if $currentFullNote}
						<NoteEditor note={$currentFullNote} bind:isEditing {saveNote} />
					{:else}
						<div class="flex h-full flex-col items-center justify-center">
							<p class="mb-4 text-lg">None selected</p>
							<button on:click={createNewNote} class="btn-primary">Create note</button>
						</div>
					{/if}
				</main>
			</div>
		</div>

		<!-- Settings Modal -->
		{#if showSettings}
			<SettingsModal onClose={toggleSettings} />
		{/if}
	</div>
{/if}
