<script lang="ts">
  import { onMount } from 'svelte';
  import { app, handleError, refreshNotifications, showToast } from '../lib/app.svelte';
  import { connection } from '../lib/connection.svelte';
  import { gateway } from '../lib/gateway';
  import { GatewayError } from '../lib/client';
  import { t } from '../lib/i18n/index.svelte';
  import { friendCodeParam, shareLink } from '../lib/deeplink';
  import { shareTelegramLink } from '../lib/telegram';
  import type { AccountRef, FriendCode, RobotBlockEntry } from '../lib/model';

  let friends = $state<AccountRef[]>([]);
  let incoming = $state<AccountRef[]>([]);
  let blocked = $state<AccountRef[]>([]);
  // Per-game disguised-robot blocks, shown as distinct entries alongside blocked humans.
  let robotBlocks = $state<RobotBlockEntry[]>([]);
  let code = $state<FriendCode | null>(null);
  let redeemInput = $state('');

  async function load() {
    try {
      const [fl, inc, bl] = await Promise.all([
        gateway.friendsList(),
        gateway.friendsIncoming(),
        gateway.blocksList(),
      ]);
      friends = fl;
      incoming = inc;
      blocked = bl.blocked;
      robotBlocks = bl.robots;
    } catch (e) {
      handleError(e);
    }
  }

  onMount(() => {
    if (!app.profile?.isGuest) void load();
  });

  async function act(fn: () => Promise<unknown>) {
    try {
      await fn();
      await load();
      void refreshNotifications();
    } catch (e) {
      handleError(e);
    }
  }

  const respond = (id: string, accept: boolean) => act(() => gateway.friendRespond(id, accept));
  const remove = (id: string) => act(() => gateway.unfriend(id));
  const blockUser = (id: string) => act(() => gateway.block(id));
  const unblock = (id: string) => act(() => gateway.unblock(id));

  async function getCode() {
    try {
      code = await gateway.friendCodeIssue();
    } catch (e) {
      handleError(e);
    }
  }

  async function redeem() {
    const c = redeemInput.trim();
    if (!c) return;
    try {
      const friend = await gateway.friendCodeRedeem(c);
      redeemInput = '';
      showToast(t('friends.added', { name: friend.displayName }));
      await load();
    } catch (e) {
      if (e instanceof GatewayError && e.code === 'self_relation') {
        showToast(t('friends.selfInvite')); // redeeming your own code: a friendly, non-error note
      } else {
        handleError(e);
      }
    }
  }

  function codeTime(unix: number): string {
    return new Date(unix * 1000).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
  }

  async function copyCode() {
    if (!code) return;
    try {
      await navigator.clipboard.writeText(code.code);
      showToast(t('friends.codeCopied'));
    } catch {
      // Clipboard may be unavailable (insecure context); leave the code on screen.
    }
  }

  // shareInvite shares the friend-code deep link: inside Telegram via the native
  // "share to chat" picker; on the web via the system share sheet; failing both, it
  // copies the link to the clipboard.
  async function shareInvite(url: string) {
    const text = t('friends.inviteText');
    if (shareTelegramLink(url, text)) return;
    if (typeof navigator !== 'undefined' && navigator.share) {
      try {
        await navigator.share({ text, url });
        return;
      } catch {
        return; // the user dismissed the share sheet
      }
    }
    try {
      await navigator.clipboard.writeText(url);
      showToast(t('friends.linkCopied'));
    } catch {
      // Clipboard unavailable (insecure context); nothing more to do.
    }
  }
</script>

<div class="page">
  {#if app.profile?.isGuest}
    <p class="muted">{t('profile.guestLocked')}</p>
  {:else}
    <section>
      <h3>{t('friends.add')}</h3>
      <div class="addrow">
        <input
          class="codein"
          bind:value={redeemInput}
          placeholder={t('friends.codePlaceholder')}
          inputmode="numeric"
          maxlength="6"
        />
        <button class="btn" onclick={redeem} disabled={!connection.online}>{t('friends.redeem')}</button>
      </div>
      {#if code}
        {@const tg = shareLink(friendCodeParam(code.code))}
        <div class="code" data-testid="friend-code">
          <div class="coderow">
            <button class="codeval" onclick={copyCode}>{code.code}</button>
            <button class="copy" onclick={copyCode} aria-label={t('friends.copy')}>📋</button>
          </div>
          <span class="codehint">
            {t('friends.codeHint')} · {t('friends.codeExpires', { time: codeTime(code.expiresAtUnix) })}
          </span>
          {#if tg}
            <button type="button" class="link tgshare" onclick={() => shareInvite(tg)}>{t('friends.shareTelegram')}</button>
          {/if}
        </div>
      {:else}
        <button class="link" onclick={getCode} disabled={!connection.online}>{t('friends.getCode')}</button>
      {/if}
    </section>

    {#if incoming.length}
      <section>
        <h3>{t('friends.incoming')}</h3>
        {#each incoming as r (r.accountId)}
          <div class="item">
            <span class="who">{r.displayName}</span>
            <span class="acts">
              <button class="btn" onclick={() => respond(r.accountId, true)} disabled={!connection.online}>{t('friends.accept')}</button>
              <button class="ghost" onclick={() => respond(r.accountId, false)} disabled={!connection.online}>{t('friends.decline')}</button>
            </span>
          </div>
        {/each}
      </section>
    {/if}

    <section>
      <h3>{t('friends.yours')}</h3>
      {#if friends.length}
        {#each friends as f (f.accountId)}
          <div class="item">
            <span class="who">{f.displayName}</span>
            <span class="acts">
              <button class="ghost" onclick={() => remove(f.accountId)} disabled={!connection.online}>{t('friends.unfriend')}</button>
              <button class="ghost danger" onclick={() => blockUser(f.accountId)} disabled={!connection.online}>{t('friends.block')}</button>
            </span>
          </div>
        {/each}
      {:else}
        <p class="muted">{t('friends.none')}</p>
      {/if}
    </section>

    {#if blocked.length || robotBlocks.length}
      <section>
        <h3>{t('friends.blockedList')}</h3>
        {#each blocked as b (b.accountId)}
          <div class="item">
            <span class="who">{b.displayName}</span>
            <button class="ghost" onclick={() => unblock(b.accountId)} disabled={!connection.online}>{t('friends.unblock')}</button>
          </div>
        {/each}
        {#each robotBlocks as r (r.id)}
          <div class="item">
            <span class="who">{r.displayName}</span>
            <button class="ghost" onclick={() => unblock(r.id)} disabled={!connection.online}>{t('friends.unblock')}</button>
          </div>
        {/each}
      </section>
    {/if}
  {/if}
</div>

<style>
  .page {
    padding: var(--pad);
    display: flex;
    flex-direction: column;
    gap: 22px;
  }
  h3 {
    margin: 0 0 10px;
    font-size: 0.95rem;
    color: var(--text-muted);
  }
  .muted {
    color: var(--text-muted);
    margin: 0;
  }
  .addrow {
    display: flex;
    gap: 8px;
  }
  .codein {
    flex: 1;
    min-width: 0;
    padding: 10px 12px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    border-radius: var(--radius-sm);
    letter-spacing: 0.3em;
    font-size: 1.1rem;
  }
  .code {
    margin-top: 10px;
    padding: 12px 14px;
    border: 1px dashed var(--border);
    border-radius: var(--radius);
    display: flex;
    flex-direction: column;
    gap: 4px;
  }
  .coderow {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
  }
  .codeval {
    font-size: 1.8rem;
    font-weight: 700;
    letter-spacing: 0.3em;
    background: none;
    border: none;
    color: var(--text);
    padding: 0;
    cursor: pointer;
    text-align: left;
    font-family: inherit;
  }
  .copy {
    flex: 0 0 auto;
    background: none;
    border: none;
    font-size: 1.4rem;
    padding: 4px;
    cursor: pointer;
  }
  .codehint {
    font-size: 0.8rem;
    color: var(--text-muted);
  }
  .link {
    margin-top: 10px;
    background: none;
    border: none;
    color: var(--accent);
    padding: 4px 0;
    text-align: left;
  }
  .item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    background: var(--surface);
    border-radius: var(--radius-sm);
    margin-bottom: 8px;
  }
  .who {
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .acts {
    display: flex;
    gap: 8px;
    flex: 0 0 auto;
  }
  .btn {
    padding: 8px 12px;
    border: 1px solid var(--accent);
    background: var(--accent);
    color: var(--accent-text);
    border-radius: var(--radius-sm);
  }
  .ghost {
    padding: 8px 12px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    border-radius: var(--radius-sm);
  }
  .ghost.danger {
    color: var(--danger, #c0392b);
  }
</style>
