<script lang="ts">
  import { api } from '$lib/api';
  import { toast } from '$lib/toast';
  import type { XeroContact, XeroContactLinkRow, XeroStatus } from '$lib/types';

  let { data } = $props();

  let xero = $state<XeroStatus | null>(null);
  let contacts = $state<XeroContact[]>([]);
  let contactsStubbed = $state(false);
  let links = $state<XeroContactLinkRow[]>([]);
  // The contact selected in each customer's dropdown, keyed by customer id. Seeded
  // from the saved link or the server's suggested match so the operator usually
  // just confirms.
  let choice = $state<Record<number, string>>({});

  // Hydrate local state from the loader. Read only from `data` here — referencing
  // a writable state we also assign (e.g. `links`) inside the same effect would
  // retrigger it forever (svelte effect_update_depth_exceeded).
  $effect(() => {
    const nextLinks = data.links ?? [];
    xero = data.xero ?? null;
    contacts = data.contacts ?? [];
    contactsStubbed = data.contactsStubbed ?? false;
    links = nextLinks;
    choice = Object.fromEntries(
      nextLinks.map((l) => [l.customer_id, l.xero_contact_id ?? l.suggested_contact_id ?? ''])
    );
  });

  const linkedCount = $derived(links.filter((l) => l.linked).length);

  async function refresh() {
    try {
      const [status, list, rows] = await Promise.all([
        api.orderingAdmin.xeroStatus(),
        api.orderingAdmin.xeroContacts(),
        api.orderingAdmin.xeroContactLinks()
      ]);
      xero = status;
      contacts = list.contacts;
      contactsStubbed = list.stubbed;
      links = rows;
      choice = Object.fromEntries(
        rows.map((l) => [l.customer_id, l.xero_contact_id ?? l.suggested_contact_id ?? ''])
      );
    } catch {}
  }

  async function saveLink(row: XeroContactLinkRow) {
    const contactId = choice[row.customer_id];
    if (!contactId) return toast.error('Choose a Xero contact first.');
    const contact = contacts.find((c) => c.contact_id === contactId);
    try {
      await api.orderingAdmin.linkCustomerToXero(row.customer_id, {
        xero_contact_id: contactId,
        xero_contact_name: contact?.name ?? null,
        xero_contact_email: contact?.email ?? null
      });
      toast.success(`${row.customer_name} linked to ${contact?.name ?? 'Xero contact'}.`);
      await refresh();
    } catch (e) {
      toast.error(e instanceof Error ? e.message : 'Could not link customer.');
    }
  }

  async function removeLink(row: XeroContactLinkRow) {
    try {
      await api.orderingAdmin.unlinkCustomerFromXero(row.customer_id);
      toast.success(`${row.customer_name} unlinked.`);
      await refresh();
    } catch (e) {
      toast.error(e instanceof Error ? e.message : 'Could not unlink customer.');
    }
  }

  function isDirty(row: XeroContactLinkRow): boolean {
    const sel = choice[row.customer_id] ?? '';
    return !!sel && sel !== (row.xero_contact_id ?? '');
  }
</script>

<section class="surface-card">
  <h2>Xero connection</h2>
  {#if xero}
    <p class="muted">Mode: <strong>{xero.connection.mode}</strong> · {xero.connection.configured ? 'Configured' : 'Not configured (stub mode)'}</p>
    {#if xero.connection.missing_env.length}
      <p class="muted">Missing env: {xero.connection.missing_env.join(', ')}</p>
    {/if}
    <p class="muted">
      Customers linked to a Xero contact:
      <strong>{xero.contact_links.linked}</strong> of {xero.contact_links.total}
      {#if xero.contact_links.unlinked}· <span class="warn-text">{xero.contact_links.unlinked} unlinked</span>{/if}
    </p>
  {:else}
    <p class="empty">Could not load integration status.</p>
  {/if}
</section>

<section class="surface-card">
  <div class="card-head">
    <h2>Customer ↔ Xero contact mapping</h2>
    <span class="count">{linkedCount}/{links.length} linked</span>
  </div>
  <p class="muted">
    Link each customer in our database to its contact in Xero. Once linked, that
    customer's order invoices are raised against the matched Xero contact instead
    of being matched by code.
    {#if contactsStubbed}<br />Showing <strong>sample</strong> Xero contacts — live contacts appear once Xero credentials are configured.{/if}
  </p>

  {#if !links.length}
    <p class="empty">No customers yet.</p>
  {:else}
    <table>
      <thead>
        <tr><th>Customer</th><th>Code</th><th>Xero contact</th><th>Status</th><th></th></tr>
      </thead>
      <tbody>
        {#each links as row (row.customer_id)}
          <tr>
            <td>{row.customer_name}</td>
            <td>{row.client_code}</td>
            <td>
              <select bind:value={choice[row.customer_id]}>
                <option value="">— Not linked —</option>
                {#each contacts as c (c.contact_id)}
                  <option value={c.contact_id}>{c.name}{c.email ? ` (${c.email})` : ''}</option>
                {/each}
              </select>
              {#if !row.linked && row.suggested_contact_id}
                <span class="hint">suggested match</span>
              {/if}
            </td>
            <td>
              {#if row.linked}
                <span class="pill pos">Linked</span>
              {:else}
                <span class="pill warn">Unlinked</span>
              {/if}
            </td>
            <td class="row-actions">
              <button
                class="primary sm"
                onclick={() => saveLink(row)}
                disabled={!choice[row.customer_id] || (row.linked && !isDirty(row))}
              >
                {row.linked ? 'Update' : 'Link'}
              </button>
              {#if row.linked}
                <button class="link" onclick={() => removeLink(row)}>Unlink</button>
              {/if}
            </td>
          </tr>
        {/each}
      </tbody>
    </table>
  {/if}
</section>

<section class="surface-card">
  <h2>Recent syncs</h2>
  {#if !xero || !xero.recent_syncs.length}
    <p class="empty">No Xero submissions yet.</p>
  {:else}
    <ul class="mini">
      {#each xero.recent_syncs as s (s.id)}
        <li>Order {s.order_id} · {s.status} · {s.xero_invoice_id ?? '—'} · {new Date(s.created_at).toLocaleString('en-AU')}</li>
      {/each}
    </ul>
  {/if}
</section>

<style>
  .count { font-size: 0.78rem; font-weight: 600; color: var(--color-text-muted); }
  .row-actions { display: flex; align-items: center; gap: 0.6rem; white-space: nowrap; }
  .primary.sm { min-height: 1.9rem; padding: 0.3rem 0.7rem; font-size: 0.8rem; }
  .hint { display: block; margin-top: 0.2rem; font-size: 0.68rem; color: var(--color-info); }
  .warn-text { color: var(--color-warning-text); font-weight: 600; }
</style>
