// ---------------------------------------------------------------------------
// Live-tail merge hook (sub-project 5, Phase 5 Task 20).
//
// Reads the matching slice of `useTailStore` and returns a single array:
// `baseItems` first (in the order the caller supplied them), then any new
// tail items in arrival order, with duplicates of base ids removed.
//
// Design notes:
// - The dedup runs against `baseItems` (not the other way around) because
//   the base list is the authoritative snapshot from the page's JSON
//   fetch — the tail slice is an opportunistic delta, so the base wins
//   when an id appears in both.
// - The optional `filterFn` is applied to the tail slice AFTER dedup so a
//   page-specific filter (e.g. "only show me submitted claims") doesn't
//   accidentally include items that were already filtered out of base.
// - We don't `useMemo` here: `baseItems` is a new array reference on
//   every render of the caller, so memo deps would invalidate anyway.
//   The merge is cheap (one Set build + two filters) and zustand's
//   selector ensures we only re-render when the slice actually changes.
// ---------------------------------------------------------------------------

import { useTailStore } from "@/store/tail-store";
import type { TailResource } from "@/lib/tail-stream";

export function useMergedTail<T extends { id: string }>(
  resource: TailResource,
  baseItems: T[],
  filterFn?: (item: T) => boolean,
): T[] {
  // Select the slice that matches the resource. We return a fresh array
  // each time so the consumer gets a stable iteration order even when
  // zustand hands us a new container (Record or array) reference.
  const tailSlice = useTailStore((s) => {
    switch (resource) {
      case "claims": {
        // The store keys claims by id in a Record for O(1) updates, but
        // also keeps an `claimOrder` array so we can iterate in arrival
        // order. Filter out any holes (defensive — shouldn't happen but
        // type-narrows the result to Claim[]).
        const out: unknown[] = [];
        for (const id of s.claimOrder) {
          const v = s.claims[id];
          if (v !== undefined) out.push(v);
        }
        return out;
      }
      case "remittances": {
        const out: unknown[] = [];
        for (const id of s.remitOrder) {
          const v = s.remittances[id];
          if (v !== undefined) out.push(v);
        }
        return out;
      }
      case "activity":
        // Activity is already an array — the store appends in arrival
        // order, so iteration order is exactly what we want.
        return s.activity as unknown[];
    }
  });

  const baseIds = new Set<string>();
  for (const b of baseItems) baseIds.add(b.id);

  const tailAfterDedup: unknown[] = [];
  for (const t of tailSlice) {
    const id = (t as { id: string }).id;
    if (baseIds.has(id)) continue;
    tailAfterDedup.push(t);
  }

  const tailAfterFilter = filterFn
    ? tailAfterDedup.filter((t) => filterFn(t as T))
    : tailAfterDedup;

  return [...baseItems, ...(tailAfterFilter as T[])];
}
