import { reblogStatus, unreblogStatus } from 'src/lib/api'
import type { Status } from 'src/lib/api-types'
import { queryKeys } from 'src/lib/queries/keys'
import { isSyntheticRemoteId } from 'src/lib/remote-outbox'
import { emit } from 'src/lib/tapestry/emit'
import { postScopeKeys, useCacheMutation } from './cacheMutation'
import { updatePostInCache } from './updatePostInCache'

type ShareMutateType = {
  id: string
  isShared: boolean
  profileId?: string
}

export function useShareMutation({ profileId }: { profileId?: string } = {}) {
  const profileKey = (vars: ShareMutateType) => {
    const uid = vars.profileId ?? profileId
    return uid ? [queryKeys.posts.byUser(uid)] : []
  }

  const { mutate, isPending } = useCacheMutation<Status | undefined, ShareMutateType>({
    label: ({ isShared }) => (isShared ? 'Unsharing…' : 'Sharing…'),
    mutationFn: (vars) =>
      vars.isShared
        ? (unreblogStatus({ id: vars.id }) as Promise<Status>)
        : (reblogStatus({ id: vars.id }) as Promise<Status>),

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

    applyOptimistic: (qc, vars) => {
      updatePostInCache(
        qc,
        vars.id,
        (post) => ({
          ...post,
          reblogged: !vars.isShared,
          reblogs_count: vars.isShared
            ? Math.max(0, (post.reblogs_count ?? 0) - 1)
            : (post.reblogs_count ?? 0) + 1,
        }),
        profileKey(vars)
      )
    },

    reconcile: (qc, data, vars) => {
      if (!data) return
      // Mastodon's POST /reblog returns a wrapper Status whose `reblog`
      // field is the original; unwrap so we patch the original's id (the
      // row in the feed caches), not the wrapper. Pixelfed and the
      // unreblog path return the original directly — fall through.
      const target = (data as Status & { reblog?: Status | null }).reblog ?? data
      updatePostInCache(qc, target.id, () => target, profileKey(vars))
    },

    onSuccess: (_data, vars) => {
      if (!vars.isShared) emit('R')
    },
  })

  const handleShare = async (id: string, isShared: boolean, statusProfileId?: string) => {
    if (isSyntheticRemoteId(id)) return
    try {
      await mutate({
        id,
        isShared,
        profileId: statusProfileId !== undefined ? statusProfileId : profileId,
      })
    } catch (_error) {}
  }

  return { handleShare, isSharePending: isPending }
}
