import { likeStatus, unlikeStatus } from 'src/lib/api'
import type { Account, Status } from 'src/lib/api-types'
import type { LinkPaginatedResponse } from 'src/lib/pagination'
import { queryKeys } from 'src/lib/queries/keys'
import { isSyntheticRemoteId } from 'src/lib/remote-outbox'
import { emit } from 'src/lib/tapestry/emit'
import { AccountStore } from 'src/state/accountStore'
import { postScopeKeys, useCacheMutation } from './cacheMutation'
import { updatePostInCache } from './updatePostInCache'

type LikesInfiniteCache = {
  pages: LinkPaginatedResponse<Account>[]
  pageParams: unknown[]
}

type LikeMutateType = {
  type: 'like' | 'unlike'
  id: string
  profileId?: string
}

export function useLikeMutation({
  onSuccess,
  profileId,
}: {
  onSuccess?: (data: any, variables: LikeMutateType) => void
  profileId?: string
} = {}) {
  const profileKey = (vars: LikeMutateType) => {
    const uid = vars.profileId ?? profileId
    return uid ? [queryKeys.posts.byUser(uid)] : []
  }

  const { mutate, isPending } = useCacheMutation<Status, LikeMutateType>({
    mutationFn: (vars) => (vars.type === 'like' ? likeStatus(vars) : unlikeStatus(vars)),

    snapshotKeys: (vars) => postScopeKeys(vars.id, profileKey(vars)),

    applyOptimistic: (qc, vars) => {
      const isLike = vars.type === 'like'
      const me = AccountStore.activeUserCache()
      updatePostInCache(
        qc,
        vars.id,
        (post) => ({
          ...post,
          favourited: isLike,
          favourites_count: isLike
            ? (post.favourites_count ?? 0) + 1
            : Math.max(0, (post.favourites_count ?? 1) - 1),
        }),
        profileKey(vars)
      )

      // Prepend (or filter) the active user inside the `/post/likes/[id]`
      // paginated cache so tapping the count straight after liking shows
      // the user in the list, rather than waiting for the next refetch.
      // Dedupes on id so a like → unlike → like sequence stays single-entry.
      if (me) {
        qc.setQueryData<LikesInfiniteCache | undefined>(
          queryKeys.posts.likes(vars.id),
          (old) => {
            if (!old?.pages?.length) return old
            const pages = old.pages.map((page, i) => {
              const filtered = page.data.filter((a) => a.id !== me.id)
              const data = isLike && i === 0 ? [me, ...filtered] : filtered
              return { ...page, data }
            })
            return { ...old, pages }
          }
        )
      }
    },

    reconcile: (qc, data, vars) => {
      updatePostInCache(qc, data.id, () => data, profileKey(vars))
    },

    onSuccess: (data, vars) => {
      emit(vars.type === 'like' ? 'L' : 'u')
      onSuccess?.(data, vars)
    },
  })

  const handleLike = async (id: string, liked: boolean, statusProfileId?: string) => {
    // Synthetic remote rows (assembled from an actor's AP outbox when the
    // home server returns no statuses) have no home-instance id, so a
    // like POST would 404. Gate here rather than per-call site so every
    // surface that renders a synthetic row is covered.
    if (isSyntheticRemoteId(id)) return
    try {
      await mutate({
        type: liked ? 'like' : 'unlike',
        id,
        profileId: statusProfileId !== undefined ? statusProfileId : profileId,
      })
    } catch (_error) {}
  }

  return { handleLike, isLikePending: isPending }
}
