<script lang="ts">
  import { Search } from 'lucide-svelte';

  import { label } from '$lib/ordering/format';
  import type { CustomerVisibilityRow } from '$lib/types';

  let {
    rows,
    onToggle,
    onBulk
  }: {
    rows: CustomerVisibilityRow[];
    onToggle: (row: CustomerVisibilityRow) => void | Promise<void>;
    onBulk: (productIds: number[], visible: boolean) => void | Promise<void>;
  } = $props();

  let query = $state('');

  const visibleCount = $derived(rows.filter((r) => r.visible).length);

  const filtered = $derived.by(() => {
    const q = query.trim().toLowerCase();
    if (!q) return rows;
    return rows.filter(
      (r) => r.name.toLowerCase().includes(q) || r.sku.toLowerCase().includes(q)
    );
  });

  // Group the filtered rows by category, keeping first-seen order so the list is
  // stable as the search narrows. Each group carries its own visible tally so the
  // header can show progress without a second pass at render time.
  const groups = $derived.by(() => {
    const map = new Map<string, CustomerVisibilityRow[]>();
    for (const row of filtered) {
      const list = map.get(row.category) ?? [];
      list.push(row);
      map.set(row.category, list);
    }
    return [...map.entries()].map(([category, items]) => ({
      category,
      items,
      visible: items.filter((i) => i.visible).length
    }));
  });

  /** Product ids in `set` whose current visibility differs from `target`. */
  function idsToChange(set: CustomerVisibilityRow[], target: boolean): number[] {
    return set.filter((r) => r.visible !== target).map((r) => r.product_id);
  }

  function setGroup(items: CustomerVisibilityRow[], visible: boolean) {
    void onBulk(idsToChange(items, visible), visible);
  }

  function setFiltered(visible: boolean) {
    void onBulk(idsToChange(filtered, visible), visible);
  }
</script>

<div class="visibility-manager">
  <div class="vis-toolbar">
    <label class="vis-search">
      <Search size={15} strokeWidth={2} aria-hidden="true" />
      <input
        type="search"
        bind:value={query}
        placeholder="Search products or SKU"
        aria-label="Search products"
      />
    </label>
    <div class="vis-summary">
      <span class="count-strong">{visibleCount}</span>
      <span class="count-of">of {rows.length} visible</span>
    </div>
  </div>

  {#if rows.length}
    <div class="vis-bulk">
      <span>{filtered.length === rows.length ? 'All products' : `${filtered.length} shown`}</span>
      <div class="vis-bulk-actions">
        <button class="link" type="button" onclick={() => setFiltered(true)}>Show all</button>
        <span class="dot" aria-hidden="true">·</span>
        <button class="link" type="button" onclick={() => setFiltered(false)}>Hide all</button>
      </div>
    </div>

    {#if filtered.length}
      <div class="vis-groups">
        {#each groups as group (group.category)}
          <section class="vis-group">
            <header class="vis-group-head">
              <h4>
                {label(group.category)}
                <span class="vis-group-count">{group.visible}/{group.items.length}</span>
              </h4>
              <div class="vis-group-actions">
                <button class="link" type="button" onclick={() => setGroup(group.items, true)}>All</button>
                <span class="dot" aria-hidden="true">·</span>
                <button class="link" type="button" onclick={() => setGroup(group.items, false)}>None</button>
              </div>
            </header>
            <ul class="vis-list">
              {#each group.items as row (row.product_id)}
                <li>
                  <label class="vis-row" class:on={row.visible}>
                    <input
                      type="checkbox"
                      checked={row.visible}
                      onchange={() => onToggle(row)}
                    />
                    <span class="vis-name">{row.name}</span>
                    <span class="vis-sku">{row.sku}</span>
                  </label>
                </li>
              {/each}
            </ul>
          </section>
        {/each}
      </div>
    {:else}
      <p class="vis-empty">No products match “{query}”.</p>
    {/if}
  {:else}
    <p class="vis-empty">No products in the catalogue yet. Add products to control what this customer can order.</p>
  {/if}
</div>

<style>
  .visibility-manager {
    display: grid;
    gap: 0.85rem;
  }

  /* ── Toolbar: search + running visible tally ─────────────────── */
  .vis-toolbar {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
  }

  .vis-search {
    flex: 1;
    min-width: 12rem;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.7rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-control);
    background: var(--color-input-bg);
    color: var(--color-text-muted);
    transition: border-color 140ms cubic-bezier(0.22, 1, 0.36, 1),
      box-shadow 140ms cubic-bezier(0.22, 1, 0.36, 1);
  }

  .vis-search:focus-within {
    border-color: var(--color-brand);
    background: var(--color-bg-surface);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-brand) 20%, transparent);
  }

  .vis-search input {
    flex: 1;
    min-width: 0;
    border: none;
    outline: none;
    background: transparent;
    color: var(--color-text-primary);
    font: inherit;
  }

  .vis-summary {
    display: inline-flex;
    align-items: baseline;
    gap: 0.32rem;
    white-space: nowrap;
  }

  .count-strong {
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--color-brand);
    font-variant-numeric: tabular-nums;
  }

  .count-of {
    font-size: 0.78rem;
    color: var(--color-text-muted);
  }

  /* ── Bulk row ────────────────────────────────────────────────── */
  .vis-bulk {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    padding-bottom: 0.55rem;
    border-bottom: 1px solid var(--color-divider);
    font-size: 0.78rem;
    color: var(--color-text-muted);
  }

  .vis-bulk-actions,
  .vis-group-actions {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
  }

  .dot {
    color: var(--color-text-muted);
  }

  /* ── Category groups ─────────────────────────────────────────── */
  .vis-groups {
    display: grid;
    gap: 1.05rem;
  }

  .vis-group-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    margin-bottom: 0.45rem;
  }

  .vis-group-head h4 {
    margin: 0;
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    font-size: 0.74rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-secondary);
  }

  .vis-group-count {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
  }

  .vis-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: 0.4rem;
  }

  .vis-row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: 0.6rem;
    padding: 0.5rem 0.65rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-control);
    background: var(--color-bg-surface);
    cursor: pointer;
    transition: border-color 140ms cubic-bezier(0.22, 1, 0.36, 1),
      background-color 140ms cubic-bezier(0.22, 1, 0.36, 1);
  }

  .vis-row:hover {
    border-color: color-mix(in srgb, var(--color-brand) 35%, var(--color-border));
  }

  .vis-row.on {
    background: color-mix(in srgb, var(--color-brand-tint) 55%, var(--color-bg-surface));
    border-color: color-mix(in srgb, var(--color-brand) 28%, var(--color-border));
  }

  .vis-row input {
    accent-color: var(--color-brand);
    width: 1rem;
    height: 1rem;
    cursor: pointer;
  }

  .vis-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--color-text-primary);
  }

  .vis-sku {
    font-size: 0.72rem;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }

  .vis-empty {
    margin: 0.3rem 0;
    padding: 1rem;
    border: 1px dashed var(--color-border);
    border-radius: var(--radius-control);
    color: var(--color-text-muted);
    font-size: 0.84rem;
    text-align: center;
  }
</style>
