<!--
Pending invitations panel for the lobby `games` section. Surfaces
user-bound invites that have not been redeemed or declined yet, with
accept / decline actions. Accepted invites move the inviting game into
`active-past`; declined invites disappear from the list.
-->
<script lang="ts">
	import { onMount } from "svelte";
	import { account } from "$lib/account-store.svelte";
	import { i18n } from "$lib/i18n/index.svelte";
	import { lobbyData, describeLobbyError } from "$lib/lobby-data.svelte";
	import LobbyShell from "./lobby-shell.svelte";
	import {
		declineInvite,
		listMyGames,
		redeemInvite,
		type InviteSummary,
	} from "../../api/lobby";

	let actionInFlight = $state<string | null>(null);
	let actionError = $state<string | null>(null);

	onMount(() => {
		lobbyData.ensure().then((client) => {
			if (client !== null) {
				account.ensure(client).catch(() => {});
			}
		});
	});

	async function acceptInvite(invite: InviteSummary): Promise<void> {
		const client = lobbyData.client;
		if (client === null) return;
		actionInFlight = invite.inviteId;
		actionError = null;
		try {
			await redeemInvite(client, invite.gameId, invite.inviteId);
			lobbyData.removeInvitation(invite.inviteId);
			lobbyData.setMyGames(await listMyGames(client));
		} catch (err) {
			actionError = describeLobbyError(err);
		} finally {
			actionInFlight = null;
		}
	}

	async function rejectInvite(invite: InviteSummary): Promise<void> {
		const client = lobbyData.client;
		if (client === null) return;
		actionInFlight = invite.inviteId;
		actionError = null;
		try {
			await declineInvite(client, invite.gameId, invite.inviteId);
			lobbyData.removeInvitation(invite.inviteId);
		} catch (err) {
			actionError = describeLobbyError(err);
		} finally {
			actionInFlight = null;
		}
	}
</script>

<LobbyShell>
	{#if lobbyData.configError !== null}
		<p role="alert" data-testid="account-error">{lobbyData.configError}</p>
	{:else if lobbyData.error !== null}
		<p role="alert" data-testid="lobby-error">{lobbyData.error}</p>
	{/if}

	{#if actionError !== null}
		<p role="alert" data-testid="lobby-invitation-error">{actionError}</p>
	{/if}

	<section data-testid="lobby-games-invitations-section">
		<h2>{i18n.t("lobby.section.invitations")}</h2>
		{#if lobbyData.loading}
			<p role="status">{i18n.t("lobby.list_loading")}</p>
		{:else if lobbyData.invitations.length === 0}
			<p data-testid="lobby-invitations-empty">{i18n.t("lobby.invitations.empty")}</p>
		{:else}
			<ul class="card-list">
				{#each lobbyData.invitations as invite (invite.inviteId)}
					<li class="card">
						<strong>{invite.raceName}</strong>
						<span class="meta">{invite.gameId}</span>
						<div class="actions">
							<button
								onclick={() => acceptInvite(invite)}
								disabled={actionInFlight === invite.inviteId}
								data-testid="lobby-invite-accept"
							>
								{i18n.t("lobby.invitation.accept")}
							</button>
							<button
								onclick={() => rejectInvite(invite)}
								disabled={actionInFlight === invite.inviteId}
								data-testid="lobby-invite-decline"
							>
								{i18n.t("lobby.invitation.decline")}
							</button>
						</div>
					</li>
				{/each}
			</ul>
		{/if}
	</section>
</LobbyShell>

<style>
	section { margin-bottom: var(--space-6); }
	section h2 { font-size: var(--text-lg); margin: 0 0 var(--space-3); }
	.card-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: var(--space-2); }
	.card {
		display: flex;
		flex-direction: column;
		gap: var(--space-1);
		padding: var(--space-3);
		border: 1px solid var(--color-border);
		border-radius: var(--radius-md);
		background: var(--color-surface-raised);
		text-align: left;
		font: inherit;
		width: 100%;
	}
	.meta { color: var(--color-text-muted); font-size: var(--text-sm); }
	.actions { display: flex; gap: var(--space-2); margin-top: var(--space-1); }
</style>
