<script lang="ts">
	import { getContext } from 'svelte';
	import type { Writable } from 'svelte/store';

	type ChatListI18n = {
		t: (key: string, options?: Record<string, unknown>) => string;
	};

	const i18n: Writable<ChatListI18n> = getContext('i18n');

	import dayjs from 'dayjs';
	import localizedFormat from 'dayjs/plugin/localizedFormat';
	import { getTimeRange } from '$lib/utils';
	import ChevronUp from '$lib/components/icons/ChevronUp.svelte';
	import ChevronDown from '$lib/components/icons/ChevronDown.svelte';
	import ChevronLeft from '$lib/components/icons/ChevronLeft.svelte';
	import ChevronRight from '$lib/components/icons/ChevronRight.svelte';
	import Tooltip from '$lib/components/common/Tooltip.svelte';
	import Spinner from '$lib/components/common/Spinner.svelte';
	import { chatId, socket } from '$lib/stores';

	dayjs.extend(localizedFormat);

	type ChatListItem = {
		id: string;
		title?: string;
		updated_at?: number | null;
		created_at?: number | null;
		last_read_at?: number | null;
		active?: boolean;
		time_range?: string;
		user_id?: string;
		owner_name?: string;
		[key: string]: unknown;
	};

	export let chats: ChatListItem[] = [];

	export let chatListLoading = false;
	export let showOwnerInfo = false;
	export let page = 1;
	export let total = 0;
	export let perPage = 10;
	export let orderBy: 'title' | 'updated_at' = 'updated_at';
	export let direction: 'asc' | 'desc' = 'desc';
	export let onPageChange: (page: number) => void | Promise<void> = () => {};
	export let onSort: (key: 'title' | 'updated_at') => void | Promise<void> = () => {};

	let chatList: ChatListItem[] | null = null;
	let totalPages = 1;
	let pages: (number | 'ellipsis')[] = [];

	const init = async () => {
		if (chats.length === 0) {
			chatList = [];
		} else {
			chatList = chats.map((chat) => ({
				...chat,
				time_range: getTimeRange(chat.updated_at)
			}));
		}
	};

	const setSortKey = (key: 'title' | 'updated_at') => {
		onSort(key);
	};

	const markChatRead = (chat: ChatListItem, unread: boolean) => {
		if (!unread) {
			return;
		}

		const lastReadAt = Date.now() / 1000;
		chatList = (chatList ?? []).map((item) =>
			item.id === chat.id ? { ...item, last_read_at: lastReadAt } : item
		);

		$socket?.emit('events:chat', {
			chat_id: chat.id,
			data: { type: 'last_read_at' }
		});
	};

	const buildPages = (currentPage: number, pageCount: number): (number | 'ellipsis')[] => {
		if (pageCount <= 7) {
			return Array.from({ length: pageCount }, (_, i) => i + 1);
		}

		const items: (number | 'ellipsis')[] = [1];
		if (currentPage > 3) {
			items.push('ellipsis');
		}

		const start = Math.max(2, currentPage - 1);
		const end = Math.min(pageCount - 1, currentPage + 1);
		for (let i = start; i <= end; i++) {
			items.push(i);
		}

		if (currentPage < pageCount - 2) {
			items.push('ellipsis');
		}
		items.push(pageCount);

		return items;
	};

	$: if (chats) {
		init();
	}

	$: totalPages = Math.max(1, Math.ceil(total / perPage));
	$: pages = buildPages(page, totalPages);
</script>

{#if chatList}
	{#if chatList.length > 0}
		<div class="flex text-xs font-normal mb-1 items-center -mr-0.5">
			<button
				class="px-1.5 py-1 cursor-pointer select-none basis-3/5"
				on:click={() => setSortKey('title')}
			>
				<div class="flex gap-1.5 items-center">
					{$i18n.t('Title')}

					{#if orderBy === 'title'}
						<span class="font-normal"
							>{#if direction === 'asc'}
								<ChevronUp className="size-2" />
							{:else}
								<ChevronDown className="size-2" />
							{/if}
						</span>
					{:else}
						<span class="invisible">
							<ChevronUp className="size-2" />
						</span>
					{/if}
				</div>
			</button>
			<button
				class="px-1.5 py-1 cursor-pointer select-none hidden sm:flex sm:basis-2/5 justify-end"
				on:click={() => setSortKey('updated_at')}
			>
				<div class="flex gap-1.5 items-center">
					{$i18n.t('Updated at')}

					{#if orderBy === 'updated_at'}
						<span class="font-normal"
							>{#if direction === 'asc'}
								<ChevronUp className="size-2" />
							{:else}
								<ChevronDown className="size-2" />
							{/if}
						</span>
					{:else}
						<span class="invisible">
							<ChevronUp className="size-2" />
						</span>
					{/if}
				</div>
			</button>
		</div>
	{/if}

	<div class="text-left text-sm w-full mb-3">
		{#if chatList.length === 0}
			<div
				class="text-xs text-gray-500 dark:text-gray-400 text-center px-5 min-h-20 w-full h-full flex justify-center items-center"
			>
				{$i18n.t('No chats found')}
			</div>
		{/if}

		{#each chatList as chat, idx (chat.id)}
			{@const unread =
				chat.id !== $chatId &&
				!chat.active &&
				(chat.last_read_at == null ||
					(chat.updated_at != null && chat.updated_at > chat.last_read_at))}
			{#if (idx === 0 || (idx > 0 && chat.time_range !== chatList[idx - 1].time_range)) && chat?.time_range}
				<div
					class="w-full text-xs text-gray-500 dark:text-gray-500 font-normal {idx === 0
						? ''
						: 'pt-5'} pb-2 px-2"
				>
					{$i18n.t(chat.time_range)}
					<!-- localisation keys for time_range to be recognized from the i18next parser (so they don't get automatically removed):
							{$i18n.t('Today')}
							{$i18n.t('Yesterday')}
							{$i18n.t('Previous 7 days')}
							{$i18n.t('Previous 30 days')}
							{$i18n.t('January')}
							{$i18n.t('February')}
							{$i18n.t('March')}
							{$i18n.t('April')}
							{$i18n.t('May')}
							{$i18n.t('June')}
							{$i18n.t('July')}
							{$i18n.t('August')}
							{$i18n.t('September')}
							{$i18n.t('October')}
							{$i18n.t('November')}
							{$i18n.t('December')}
							-->
				</div>
			{/if}

			<a
				class=" w-full flex justify-between items-center rounded-lg text-sm py-2 px-3 hover:bg-gray-50 dark:hover:bg-gray-850"
				draggable="false"
				href={`/c/${chat.id}`}
				on:click={() => markChatRead(chat, unread)}
			>
				<div class="flex min-w-0 items-center w-full sm:basis-3/5">
					{#if chat.active}
						<div class="shrink-0 self-center pr-2">
							<Spinner className="size-3" />
						</div>
					{:else if unread}
						<div class="shrink-0 self-center pr-2.5 flex transition-opacity duration-300">
							<div class="size-1.5 bg-sky-500 rounded-full"></div>
						</div>
					{/if}

					<div
						class="text-ellipsis line-clamp-1 min-w-0 {unread
							? 'font-normal text-gray-800 dark:text-gray-200'
							: ''}"
					>
						{chat?.title}
					</div>
				</div>

				<div class="hidden sm:flex sm:basis-2/5 items-center justify-end gap-2">
					<div class=" text-gray-500 dark:text-gray-400 text-xs">
						{dayjs((chat.updated_at ?? chat.created_at ?? 0) * 1000).calendar()}
					</div>

					{#if showOwnerInfo && chat.user_id && chat.owner_name}
						<Tooltip content={chat.owner_name}>
							<img
								src="/api/v1/users/{chat.user_id}/profile/image"
								alt=""
								class="size-4 rounded-full shrink-0 object-cover"
							/>
						</Tooltip>
					{/if}
				</div>
			</a>
		{/each}

		{#if totalPages > 1}
			<div class="flex items-center justify-center gap-1.5 pt-2">
				<button
					class="inline-flex size-7 items-center justify-center rounded-lg text-xs font-medium text-gray-500 transition hover:bg-gray-50 hover:text-gray-700 disabled:cursor-not-allowed disabled:opacity-25 dark:text-gray-500 dark:hover:bg-gray-850 dark:hover:text-gray-300"
					disabled={chatListLoading || page <= 1}
					aria-label={$i18n.t('Previous page')}
					on:click={() => onPageChange(page - 1)}
				>
					<ChevronLeft className="size-3.5" strokeWidth="2" />
				</button>

				{#each pages as item, index (item === 'ellipsis' ? `ellipsis-${index}` : item)}
					{#if item === 'ellipsis'}
						<span
							class="inline-flex size-7 items-center justify-center text-xs text-gray-400 select-none dark:text-gray-600"
						>
							...
						</span>
					{:else}
						<button
							class="inline-flex size-7 items-center justify-center rounded-lg text-xs font-medium transition hover:bg-gray-50 hover:text-gray-700 dark:hover:bg-gray-850 dark:hover:text-gray-300 {item ===
							page
								? 'bg-gray-50 text-gray-800 dark:bg-gray-850 dark:text-gray-100'
								: 'text-gray-500 dark:text-gray-500'}"
							aria-label={`Page ${item}`}
							aria-current={item === page ? 'page' : undefined}
							on:click={() => onPageChange(item)}
						>
							{item}
						</button>
					{/if}
				{/each}

				<button
					class="inline-flex size-7 items-center justify-center rounded-lg text-xs font-medium text-gray-500 transition hover:bg-gray-50 hover:text-gray-700 disabled:cursor-not-allowed disabled:opacity-25 dark:text-gray-500 dark:hover:bg-gray-850 dark:hover:text-gray-300"
					disabled={chatListLoading || page >= totalPages}
					aria-label={$i18n.t('Next page')}
					on:click={() => onPageChange(page + 1)}
				>
					<ChevronRight className="size-3.5" strokeWidth="2" />
				</button>
			</div>
		{/if}
	</div>
{/if}
