<script lang="ts">
	import EntryList from '$lib/components/widgets/EntryList.svelte';
	import EntityList from '$lib/components/widgets/EntityList.svelte';
	import type { Widget } from '$lib/components/EntryView.svelte';
	import EntryView from '$lib/components/EntryView.svelte';
	import { Query, UpListing } from '@upnd/upend';
	import { Any, Variable } from '@upnd/upend/query';
	import UpObject from '$lib/components/display/UpObject.svelte';
	import UpObjectCard from '$lib/components/display/UpObjectCard.svelte';
	import Spinner from '$lib/components/utils/Spinner.svelte';
	import api from '$lib/api';
	import { query } from '$lib/entity';
	import { vaultInfo } from '$lib/util/info';
	import { updateTitle } from '$lib/util/title';
	import { i18n } from '$lib/i18n';
	import { ATTR_ADDED, ATTR_IN, ATTR_KEY, ATTR_LABEL, HIER_ROOT_ADDR } from '@upnd/upend/constants';
	import UpLink from '$lib/components/display/UpLink.svelte';
	import { goto } from '$app/navigation';

	const roots = (async () => {
		const data = await api.fetchRoots();
		const listing = new UpListing(data);
		return Object.values(listing.objects)
			.filter((obj) => Boolean(obj.attr[ATTR_LABEL]))
			.map((obj) => [obj.address, obj.identify().join(' | ')])
			.sort(([_, i1], [__, i2]) => i1.localeCompare(i2));
	})();

	const keyed = (async () => {
		const data = await api.query(Query.matches(Variable('keyed'), ATTR_KEY, Any));
		return Object.values(data.objects)
			.filter((obj) => !obj.get(ATTR_KEY)?.toString()?.startsWith('TYPE'))
			.sort((a, b) =>
				(a.get(ATTR_KEY)?.toString() || '').localeCompare(b.get(ATTR_KEY)?.toString() || '')
			)
			.map((obj) => obj.address);
	})();

	const groups = (async () => {
		const data = await api.query(`(matches ? "${ATTR_IN}" ?)`);

		const addresses = data.entries
			.filter((e) => e.value.t === 'Address')
			.map((e) => e.value.c) as string[];

		const sortedAddresses = [...new Set(addresses)]
			.map((address) => ({
				address,
				count: addresses.filter((a) => a === address).length
			}))
			.sort((a, b) => b.count - a.count);

		const shortlist = sortedAddresses
			.slice(0, 25)
			.filter(({ address }) => address !== HIER_ROOT_ADDR);

		const addressesString = shortlist.map(({ address }) => `@${address}`).join(' ');
		const labels = (
			await api.query(`(matches (in ${addressesString}) "${ATTR_LABEL}" ? )`)
		).entries.filter((e) => e.value.t === 'String');

		const display = shortlist.map(({ address, count }) => ({
			address,
			labels: labels
				.filter((e) => e.entity === address)
				.map((e) => e.value.c)
				.sort() as string[],
			count
		}));

		display
			.sort((a, b) => (a.labels[0] || '').localeCompare(b.labels[0] || ''))
			.sort((a, b) => b.count - a.count);

		return { groups: display, total: sortedAddresses.length };
	})();

	const { result: recentQuery } = query(`(matches ? "LAST_VISITED" ?)`);
	$: recent = ($recentQuery?.entries || [])
		.filter((e) => e.value.t == 'Number')
		.sort((a, b) => (b.value.c as number) - (a.value.c as number))
		.slice(0, 25);

	const { result: frequentQuery } = query(`(matches ? "NUM_VISITED" ?)`);
	$: frequent = ($frequentQuery?.entries || [])
		.filter((e) => e.value.t == 'Number')
		.sort((a, b) => (b.value.c as number) - (a.value.c as number))
		.slice(0, 25);

	const { result: latestQuery } = query(`(matches ? "${ATTR_ADDED}" ?)`);
	$: latest = ($latestQuery?.entries || [])
		.filter((e) => e.value.t == 'Number')
		.sort((a, b) => (b.value.c as number) - (a.value.c as number))
		.slice(0, 25);

	const shortWidgets: Widget[] = [
		{
			name: 'List',
			icon: 'list-ul',
			components: ({ entries }) => [
				{
					component: EntryList,
					props: {
						columns: 'value, entity',
						columnWidths: ['6em'],
						orderByValue: true,
						header: false,
						entries
					}
				}
			]
		},
		{
			name: 'EntityList',
			icon: 'image',
			components: ({ entries }) => [
				{
					component: EntityList,
					props: {
						entities: entries.map((e) => e.entity),
						sort: false
					}
				}
			]
		}
	];

	const longWidgets: Widget[] = [
		{
			name: 'List',
			icon: 'list-ul',
			components: ({ entries }) => [
				{
					component: EntryList,
					props: {
						columns: 'value, entity',
						columnWidths: ['13em'],
						orderByValue: true,
						header: false,
						entries
					}
				}
			]
		},
		{
			name: 'EntityList',
			icon: 'image',
			components: ({ entries }) => [
				{
					component: EntityList,
					props: {
						entities: entries.map((e) => e.entity),
						sort: false
					}
				}
			]
		}
	];

	$: updateTitle($vaultInfo?.name || $i18n.t('Home') || 'Home');
</script>

<div class="home">
	<h1>
		{$vaultInfo?.name || 'UpEnd'}
	</h1>

	<section class="roots">
		<h2>
			<UpLink text to={{ entity: HIER_ROOT_ADDR }}>{$i18n.t('Roots')}</UpLink>
		</h2>
		{#await roots}
			<Spinner centered />
		{:then data}
			<ul>
				{#each data as [address, _]}
					<li class="root">
						{#if data.length <= 2}
							<UpObjectCard {address} />
						{:else}
							<UpObject banner link {address} />
						{/if}
					</li>
				{:else}
					<li>No roots.</li>
				{/each}
			</ul>
		{/await}
	</section>

	{#await keyed then data}
		{#if data}
			<section class="keyed">
				<h2>
					<UpLink text to={{ attribute: ATTR_KEY }}>{$i18n.t('Keyed')}</UpLink>
				</h2>
				<ul>
					{#each data as address}
						<li class="root">
							<UpObject banner={data.length <= 4} link {address} />
						</li>
					{/each}
				</ul>
			</section>
		{/if}
	{/await}

	<section class="groups">
		<h2>
			<a href="/browse/groups">
				{$i18n.t('Groups')}
			</a>
		</h2>
		{#await groups}
			<Spinner centered />
		{:then data}
			<ul>
				{#each data.groups as group}
					<li class="group">
						<UpObject link address={group.address} labels={group.labels} />
						<div class="count">{group.count}</div>
					</li>
				{:else}
					<li>No groups?</li>
				{/each}
				{#if data.groups && data.total > data.groups.length}
					<li>+ {data.total - data.groups.length}...</li>
				{/if}
			</ul>
		{/await}
	</section>

	<div class="frecent">
		{#if frequent.length || $frequentQuery === undefined}
			<section class="frequent">
				<h2>{$i18n.t('Frequently visited')}</h2>
				{#if $frequentQuery == undefined}
					<Spinner centered />
				{:else}
					<EntryView
						--current-background="var(--background)"
						entries={frequent}
						widgets={shortWidgets}
					/>
				{/if}
			</section>
		{/if}
		{#if recent.length || $recentQuery === undefined}
			<section class="recent">
				<h2>{$i18n.t('Recently visited')}</h2>
				{#if $recentQuery == undefined}
					<Spinner centered />
				{:else}
					<EntryView
						--current-background="var(--background)"
						entries={recent}
						widgets={longWidgets}
					/>
				{/if}
			</section>
		{/if}
	</div>

	{#if latest.length || $latestQuery === undefined}
		<section class="latest">
			<h2>{$i18n.t('Most recently added')}</h2>
			{#if $latestQuery == undefined}
				<Spinner centered />
			{:else}
				<EntryView
					--current-background="var(--background)"
					entries={latest}
					widgets={longWidgets}
				/>
			{/if}
		</section>
	{/if}

	<div class="button store-button">
		<a href="/store">
			{$i18n.t('View store statistics')}
		</a>
	</div>

	<footer>
		<div>
			<strong>UpEnd</strong> - {$i18n.t(
				'a database for the complex, the changing, and the indeterminate'
			)}
		</div>
		<div>
			<a target="_blank" href="https://upend.dev" class="version">
				{$vaultInfo?.version || '???'}
			</a>
		</div>
	</footer>
</div>

<style lang="scss">
	.home {
		display: flex;
		flex-direction: column;
	}

	h1,
	h2 {
		text-align: center;
	}

	h1 {
		font-size: 32pt;
		font-variant: small-caps;
		margin: 2rem 0 0 0;
	}

	h2 {
		margin: 2rem 0;
	}

	.latest,
	.frecent {
		margin: 0 2rem;
	}

	.frecent {
		display: flex;
		gap: 2rem;

		& > * {
			flex-basis: 50%;
		}

		@media screen and (max-width: 600px) {
			flex-direction: column;
		}
	}

	.roots,
	.keyed {
		ul {
			list-style: none;
			padding: 0;
			margin: 0 auto;
			display: flex;
			flex-wrap: wrap;
			width: 80%;
			gap: 1rem;
		}

		li {
			flex-basis: calc(50% - 2rem / 2);

			&:only-child {
				flex-basis: 100%;
			}
		}

		.root {
			font-size: 24px;
		}
	}

	.groups {
		ul {
			list-style: none;
			padding: 0;
			margin: 0 2rem;

			display: flex;
			flex-wrap: wrap;
			gap: 0.5em;
		}

		.group {
			display: flex;
		}

		.count {
			display: inline-block;
			font-size: 0.66em;
			margin-left: 0.25em;
		}
	}

	footer {
		border-top: 1px solid var(--foreground);
		text-align: center;
		margin: 1rem 2rem 2.5rem 2rem;

		& > * {
			margin: 0.5em;
		}
	}

	.store-button {
		display: inline-block;
		padding: 1em;
		margin: 2rem auto;
	}

	.version {
		text-decoration: none;
		opacity: 0.66;
	}
</style>
