import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import toast from "react-hot-toast";

import { QUERY_KEYS } from "@/constants/QUERY_KEYS";
import { api } from "@/services/api";
import {
  bookingsService,
  type BookingListFilter,
} from "@/services/bookings.service";
import { invalidateBookingDetail } from "@/utils/queryInvalidation";
import { extractErrorMessage } from "@/utils/errorExtractor";

const parseApiError = extractErrorMessage;

export function useBookingList(filter?: BookingListFilter, enabled = true) {
  return useQuery({
    queryKey: QUERY_KEYS.BOOKINGS.list(filter),
    queryFn: () => bookingsService.list(filter),
    enabled,
  });
}

export function useBookingListSummary(filter?: BookingListFilter, enabled = true) {
  return useQuery({
    queryKey: QUERY_KEYS.BOOKINGS.listSummary(filter),
    queryFn: () => bookingsService.getListSummary(filter),
    enabled,
  });
}

export function useBookingDetail(id: string | undefined) {
  return useQuery({
    queryKey: QUERY_KEYS.BOOKINGS.byId(id ?? ""),
    queryFn: () => bookingsService.getById(id!),
    enabled: Boolean(id),
  });
}

export function useBookingMutations(bookingId: string) {
  const qc = useQueryClient();
  const onSuccess = (data: { id: string }, message: string) => {
    toast.success(message);
    void invalidateBookingDetail(qc, data.id);
  };

  const staffAccept = useMutation({
    mutationFn: (validityDays: number) =>
      api.bookings.staffAccept.call({ id: bookingId, validityDays }),
    onSuccess: (data) => onSuccess(data, "Booking accepted for approval"),
    onError: (error) => toast.error(parseApiError(error, "Failed to accept booking")),
  });

  const requestChanges = useMutation({
    mutationFn: (note: string) =>
      api.bookings.requestChanges.call({ id: bookingId, note }),
    onSuccess: (data) => onSuccess(data, "Changes requested from customer"),
    onError: (error) => toast.error(parseApiError(error, "Failed to request changes")),
  });

  const staffReject = useMutation({
    mutationFn: (reason: string) =>
      api.bookings.staffReject.call({ id: bookingId, reason }),
    onSuccess: (data) => onSuccess(data, "Booking rejected"),
    onError: (error) => toast.error(parseApiError(error, "Failed to reject booking")),
  });

  const reviewOperation = useMutation({
    mutationFn: (payload: {
      decision: "ACCEPT" | "REQUEST_CHANGES";
      note?: string;
    }) => api.bookings.reviewOperation.call({ id: bookingId, ...payload }),
    onSuccess: (data) => onSuccess(data, "Operation request reviewed"),
    onError: (error) => {
      toast.error(parseApiError(error, "Failed to review operation request"));
      // The transition may have committed even when the response errored (e.g.
      // a post-accept step failed). Refetch so the UI shows the true state
      // instead of requiring a manual refresh.
      void invalidateBookingDetail(qc, bookingId);
    },
  });

  const generateContract = useMutation({
    mutationFn: () => api.bookings.generateContract.call({ id: bookingId }),
    onSuccess: (data) => onSuccess(data, "Contract generated"),
    onError: (error) => toast.error(parseApiError(error, "Failed to generate contract")),
  });

  const signContract = useMutation({
    mutationFn: (payload: {
      role: "CUSTOMER" | "STAFF";
      signatureImageBase64: string;
      signerDisplayName: string;
      consentText?: string;
    }) => bookingsService.signContract(bookingId, payload),
    onSuccess: (data) => onSuccess(data, "Contract signed"),
    onError: (error) => toast.error(parseApiError(error, "Failed to sign contract")),
  });

  const payBooking = useMutation({
    mutationFn: () => api.bookings.payBooking.call({ id: bookingId }),
    onSuccess: (data) => onSuccess(data, "Payment completed"),
    onError: (error) => toast.error(parseApiError(error, "Failed to complete payment")),
  });

  const startTransit = useMutation({
    mutationFn: () => api.bookings.startTransit.call({ id: bookingId }),
    onSuccess: (data) => onSuccess(data, "Marked in transit"),
    onError: (error) => toast.error(parseApiError(error, "Failed to start transit")),
  });

  const complete = useMutation({
    mutationFn: () => api.bookings.complete.call({ id: bookingId }),
    onSuccess: (data) => onSuccess(data, "Booking completed"),
    onError: (error) => toast.error(parseApiError(error, "Failed to complete booking")),
  });

  const cancel = useMutation({
    mutationFn: (reason: string) =>
      api.bookings.cancel.call({ id: bookingId, reason }),
    onSuccess: (data) => onSuccess(data, "Booking cancelled"),
    onError: (error) => toast.error(parseApiError(error, "Failed to cancel booking")),
  });

  const isPending =
    staffAccept.isPending ||
    requestChanges.isPending ||
    staffReject.isPending ||
    generateContract.isPending ||
    signContract.isPending ||
    payBooking.isPending ||
    startTransit.isPending ||
    complete.isPending ||
    reviewOperation.isPending ||
    cancel.isPending;

  return {
    staffAccept,
    requestChanges,
    staffReject,
    reviewOperation,
    generateContract,
    signContract,
    payBooking,
    startTransit,
    complete,
    cancel,
    isPending,
    downloadContract: () => bookingsService.downloadContract(bookingId),
  };
}

export function useBookingEtClearanceQueue(enabled = true) {
  return useQuery({
    queryKey: QUERY_KEYS.BOOKINGS.clearanceQueue("ET"),
    queryFn: () => bookingsService.getEtClearanceQueue(),
    enabled,
  });
}

export function useBookingDjClearanceQueue(enabled = true) {
  return useQuery({
    queryKey: QUERY_KEYS.BOOKINGS.clearanceQueue("DJ"),
    queryFn: () => bookingsService.getDjClearanceQueue(),
    enabled,
  });
}
