import { useMutation, useQueryClient } from '@tanstack/react-query';
import { ticketKeys } from '../keys';
import { ticketsApi } from '../apis';
import type { AdminTicketDetail, AdminTicketMessage, PostMessageResult } from '../types';
import { useTicketViewer } from './useTicketViewer';

interface PostAdminMessageVars {
  body: string;
  /** Staff-only: a `true` posts an internal note (never reaches the user view). */
  isInternal: boolean;
  /** Client-generated id; the reconcile key so the optimistic bubble is never double-rendered (§3.5). */
  clientMessageId: string;
}

interface PostAdminMessageContext {
  previous?: AdminTicketDetail;
}

/**
 * The admin optimistic message send — the same pattern as `usePostMessage`, but over the `adminDetail(id)`
 * cache and carrying `isInternal` so a pending internal note shows its internal styling immediately.
 *
 * `onMutate` appends a **pending** `AdminTicketMessage` (with its `isInternal`) after `cancelQueries` + a
 * snapshot. `onError` rolls the thread back (composer keeps the draft + offers retry). `onSuccess` reconciles
 * the pending bubble **by `clientMessageId`** with the server message (never double-rendered). `onSettled`
 * invalidates the admin thread + the admin queues (a new note moves the queue's activity).
 */
export function usePostAdminMessage(ticketId: number) {
  const queryClient = useQueryClient();
  const { role } = useTicketViewer();

  return useMutation<PostMessageResult, unknown, PostAdminMessageVars, PostAdminMessageContext>({
    mutationFn: ({ body, isInternal, clientMessageId }) =>
      ticketsApi.postAdminMessage(ticketId, { body, isInternal, clientMessageId }),

    onMutate: async ({ body, isInternal, clientMessageId }) => {
      const key = ticketKeys.adminDetail(ticketId);
      await queryClient.cancelQueries({ queryKey: key });
      const previous = queryClient.getQueryData<AdminTicketDetail>(key);
      if (previous) {
        const pending: AdminTicketMessage = {
          id: null,
          clientMessageId,
          ticketId,
          body,
          authorRole: role,
          createdAt: new Date().toISOString(),
          isMine: true,
          isInternal,
          sendStatus: 'sending',
        };
        queryClient.setQueryData<AdminTicketDetail>(key, { ...previous, messages: [...previous.messages, pending] });
      }
      return { previous };
    },

    onError: (_err, _vars, context) => {
      if (context?.previous) queryClient.setQueryData(ticketKeys.adminDetail(ticketId), context.previous);
    },

    onSuccess: (result, { clientMessageId }) => {
      const key = ticketKeys.adminDetail(ticketId);
      const current = queryClient.getQueryData<AdminTicketDetail>(key);
      if (current) {
        queryClient.setQueryData<AdminTicketDetail>(key, {
          ...current,
          messages: current.messages.map((m) =>
            m.clientMessageId === clientMessageId
              ? { ...m, id: result.messageId, createdAt: result.sentAt, sendStatus: 'sent' }
              : m,
          ),
        });
      }
    },

    onSettled: () => {
      queryClient.invalidateQueries({ queryKey: ticketKeys.adminDetail(ticketId) });
      queryClient.invalidateQueries({ queryKey: ticketKeys.adminLists() });
    },
  });
}
