import type { InfiniteData } from '@tanstack/react-query'
import { addMastodonListMembers } from 'src/lib/api'
import type { MastodonList } from 'src/lib/api/mastodon'
import type { Account } from 'src/lib/api-types'
import type { LinkPaginatedResponse } from 'src/lib/pagination'
import { queryKeys } from 'src/lib/queries/keys'
import { useCacheMutation } from './cacheMutation'

type AddMembersVariables = {
  listId: string
  accountIds: string[]
  // Optional Account hydration — when the caller already has the full Account
  // objects (Surface C's picker) we prepend them into the optimistic cache so
  // the list-members screen renders the new rows instantly. When omitted
  // (Surface A's by-id-only path), we only touch the inverse `forAccount`
  // cache and let the per-list cache refetch on next mount.
  accounts?: Account[]
}

// Adds N accounts to one list. Optimistic update on two cache families:
//   - `lists.accounts(listId)` — prepend the new members so the per-list
//     screen renders them immediately.
//   - `lists.forAccount(accountId)` — append `listId` to each affected
//     account's inverse-lookup cache so the picker reflects membership before
//     the next refetch.
//
// On success the server returns void; the optimistic cache state is already
// correct. On error the snapshot rolls both keys back atomically — same
// guarantee `useCacheMutation` already provides for every other mutation.
export function useAddListMembersMutation() {
  return useCacheMutation<unknown, AddMembersVariables>({
    label: 'Updating list…',
    mutationFn: ({ listId, accountIds }) => addMastodonListMembers(listId, accountIds),

    snapshotKeys: ({ listId, accountIds }) => [
      queryKeys.lists.accounts(listId),
      ...accountIds.map((id) => queryKeys.lists.forAccount(id)),
    ],

    applyOptimistic: (qc, { listId, accountIds, accounts }) => {
      if (accounts && accounts.length > 0) {
        qc.setQueryData<InfiniteData<LinkPaginatedResponse<Account>>>(
          queryKeys.lists.accounts(listId),
          (prev) => {
            if (!prev || !Array.isArray(prev.pages) || prev.pages.length === 0) {
              return prev
            }
            const seen = new Set(prev.pages.flatMap((p) => p.data.map((a) => a.id)))
            const newcomers = accounts.filter((a) => !seen.has(a.id))
            if (newcomers.length === 0) return prev
            const [head, ...rest] = prev.pages
            return {
              ...prev,
              pages: [{ ...head, data: [...newcomers, ...head.data] }, ...rest],
            }
          }
        )
      }

      // Resolve the canonical MastodonList row from the catalogue so we can
      // append it into each inverse-lookup cache with the right metadata.
      const catalogue = qc.getQueryData<MastodonList[]>(queryKeys.lists.lists()) ?? []
      const listRow = catalogue.find((l) => l.id === listId)
      if (!listRow) return

      for (const accountId of accountIds) {
        qc.setQueryData<MastodonList[]>(queryKeys.lists.forAccount(accountId), (prev) => {
          if (!Array.isArray(prev)) return prev
          if (prev.some((l) => l.id === listId)) return prev
          return [...prev, listRow]
        })
      }
    },
  })
}
