<script lang="ts">
	import type { PageData } from './$types';
	import { IconOutline, IconSolid } from 'svelte-heros-v2';
	import Input from '$lib/components/Input/Input.svelte';
	import Select from '$lib/components/Input/Select.svelte';
	import { env } from '$env/dynamic/public';
	import type { User } from '$lib/server/database';
	import { buttonTriggeredRequest, resizeTableColumn } from '$lib/components/utils';
	import { browser } from '$app/environment';

	export let data: PageData;

	let headers = [
		{
			name: 'Vorname',
			key: 'firstname',
			asc: false
		},
		{
			name: 'Nachname',
			key: 'lastname',
			asc: false
		},
		{ name: 'Geburtstag', key: 'birthday', asc: false, sort: (a, b) => a.birthday - b.birthday },
		{ name: 'Telefon', key: 'telephone', asc: false, sort: (a, b) => a.telephone - b.telephone },
		{
			name: 'Username',
			key: 'username',
			asc: false
		},
		{
			name: 'Minecraft Edition',
			key: 'playertype',
			asc: false
		},
		{
			name: 'Passwort',
			key: 'password',
			asc: false
		},
		{ name: 'UUID', key: 'uuid', asc: false }
	];
	let ascHeader: (typeof headers)[0] | null = null;

	let currentPageUsers: (typeof User.prototype.dataValues)[] = [];
	let currentPageUsersRequest: Promise<void> = new Promise((resolve) => resolve());
	let usersCache: (typeof User.prototype.dataValues)[][] = [];
	let usersPerPage = 50;
	let userPage = 0;
	let userTableContainerElement: HTMLDivElement;

	function fetchPageUsers(page: number) {
		if (!browser) return;

		if (userTableContainerElement) userTableContainerElement.scrollTop = 0;

		if (usersCache[page]) {
			currentPageUsers = usersCache[page];
			return;
		}

		// eslint-disable-next-line no-async-promise-executor
		currentPageUsersRequest = new Promise(async (resolve, reject) => {
			const response = await fetch(`${env.PUBLIC_BASE_PATH}/admin/users`, {
				method: 'POST',
				body: JSON.stringify({
					limit: usersPerPage,
					from: usersPerPage * page
				})
			});
			if (response.ok) {
				const pageUsers = await response.json();
				currentPageUsers = usersCache[page] = pageUsers;
				resolve();
			} else {
				reject(Error());
			}
		});
	}

	async function sortUsers(key: string, reverse: boolean) {
		const multiplyValue = reverse ? -1 : 1;

		currentPageUsers.sort((entryA, entryB) => {
			const a = entryA[key];
			const b = entryB[key];

			switch (typeof a) {
				case 'number':
					return (a - b) * multiplyValue;
				case 'string':
					return a.localeCompare(b) * multiplyValue;
				default:
					return (a - b) * multiplyValue;
			}
		});
		currentPageUsers = currentPageUsers;
	}

	$: fetchPageUsers(userPage);

	async function updateUser(user: typeof User.prototype.dataValues) {
		const response = await fetch(`${env.PUBLIC_BASE_PATH}/admin/users`, {
			method: 'PATCH',
			body: JSON.stringify(user)
		});
		if (!response.ok) {
			throw new Error();
		}
	}

	async function deleteUser(id: number) {
		const response = await fetch(`${env.PUBLIC_BASE_PATH}/admin/users`, {
			method: 'DELETE',
			body: JSON.stringify({
				id: id
			})
		});
		if (response.ok) {
			currentPageUsers.splice(
				currentPageUsers.findIndex((v) => v.id == id),
				1
			);
			currentPageUsers = currentPageUsers;
		} else {
			throw new Error();
		}
	}
</script>

<div>
	<div class="h-[90vh] overflow-scroll" bind:this={userTableContainerElement}>
		<table class="table relative">
			<thead>
				<tr class="[&>th]:bg-base-100 [&>th]:z-[1] [&>th]:sticky [&>th]:top-0">
					<th />
					{#each headers as header}
						<th on:mousedown={(e) => resizeTableColumn(e, 5)}>
							<button
								class="flex items-center"
								on:click={() => {
									sortUsers(header.key, (ascHeader = ascHeader == header ? null : header));
								}}
							>
								{header.name}
								<span class="ml-1">
									<IconSolid
										name={ascHeader === header ? 'chevron-up-solid' : 'chevron-down-solid'}
										width="12"
										height="12"
									/>
								</span>
							</button>
						</th>
					{/each}
					<th />
				</tr>
			</thead>
			<tbody>
				{#key currentPageUsersRequest}
					{#await currentPageUsersRequest}
						{#each Array(usersPerPage) as _, i}
							<tr class="animate-pulse text-transparent">
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>{i + 1}</td>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}
									><Input type="text" disabled={true} size="sm" /></td
								>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}
									><Input type="text" disabled={true} size="sm" /></td
								>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}
									><Input type="date" disabled={true} size="sm" /></td
								>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}
									><Input type="tel" disabled={true} size="sm" /></td
								>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}
									><Input type="text" disabled={true} size="sm" /></td
								>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}
									><Select id="edition" disabled={true} size="sm">
										<option value="java">Java Edition</option>
										<option value="bedrock">Bedrock Edition</option>
										<option value="cracked">Java cracked</option>
									</Select></td
								>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}
									><Input type="text" disabled={true} size="sm" /></td
								>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}
									><Input type="text" disabled={true} size="sm" /></td
								>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}
									><div class="flex gap-1">
										<button class="btn btn-sm btn-square" disabled />
									</div></td
								>
							</tr>
						{/each}
					{:then _}
						{#each currentPageUsers as user, i}
							<tr>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>{i + 1}</td>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
									<Input type="text" bind:value={user.firstname} disabled={!user.edit} size="sm" />
								</td>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
									<Input type="text" bind:value={user.lastname} disabled={!user.edit} size="sm" />
								</td>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
									<Input
										type="date"
										value={new Date(user.birthday).toISOString().split('T')[0]}
										on:input={(e) => (user.birthday = e.detail.target.valueAsDate.toISOString())}
										disabled={!user.edit}
										size="sm"
									/>
								</td>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
									<Input type="tel" bind:value={user.telephone} disabled={!user.edit} size="sm" />
								</td>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
									<Input type="text" bind:value={user.username} disabled={!user.edit} size="sm" />
								</td>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
									<Select id="edition" bind:value={user.playertype} disabled={!user.edit} size="sm">
										<option value="java">Java Edition</option>
										<option value="bedrock">Bedrock Edition</option>
										<option value="cracked">Java cracked</option>
									</Select>
								</td>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
									<Input type="text" bind:value={user.password} disabled={!user.edit} size="sm" />
								</td>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
									<Input
										id="uuid"
										type="text"
										bind:value={user.uuid}
										disabled={!user.edit}
										size="sm"
									/>
								</td>
								<td on:mousedown={(e) => resizeTableColumn(e, 5)}>
									<div class="flex gap-1">
										{#if user.edit}
											<button
												class="btn btn-sm btn-square"
												on:click={async (e) => {
													await buttonTriggeredRequest(e, updateUser(user));
													user.edit = false;
												}}
											>
												<IconOutline name="check-outline" width="18" height="18" />
											</button>
											<button
												class="btn btn-sm btn-square"
												on:click={() => {
													user.edit = false;
													user = user.before;
												}}
											>
												<IconOutline name="no-symbol-outline" width="18" height="18" />
											</button>
										{:else}
											<button
												class="btn btn-sm btn-square"
												on:click={() => {
													user.before = structuredClone(user);
													user.edit = true;
												}}
											>
												<IconOutline name="pencil-square-outline" width="18" height="18" />
											</button>
											<button
												class="btn btn-sm btn-square"
												on:click={(e) => buttonTriggeredRequest(e, deleteUser(user.id))}
											>
												<IconOutline name="trash-outline" width="18" height="18" />
											</button>
										{/if}
									</div>
								</td>
							</tr>
						{/each}
					{/await}
				{/key}
			</tbody>
		</table>
	</div>
	<div class="flex justify-center w-full mt-4 mb-6">
		<div class="join">
			{#each Array(Math.ceil(data.count / usersPerPage) || 1) as _, i}
				<button
					class="join-item btn"
					class:btn-active={i === userPage}
					on:click={() => {
						userPage = i;
					}}>{i + 1}</button
				>
			{/each}
		</div>
	</div>
</div>

<style lang="scss">
	thead tr th,
	tbody tr td {
		@apply relative;

		&:not(:first-child) {
			@apply border-l-[1px] border-dashed;

			&::before {
				@apply absolute left-0 bottom-0 h-full w-[5px] cursor-col-resize;
				content: '';
			}
		}

		&:not(:last-child) {
			@apply border-r-[1px] border-dashed border-base-300;

			&::after {
				@apply absolute right-0 bottom-0 h-full w-[5px] cursor-col-resize;
				content: '';
			}
		}
	}
</style>
