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";

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: () => toast.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: () => toast.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: () => toast.error("Failed to reject booking"),
  });

  const reviewOperation = useMutation({
    mutationFn: (payload: {
      decision: "ACCEPT" | "REQUEST_CHANGES" | "ADJUST_PRICE";
      note?: string;
      amount?: number;
    }) => api.bookings.reviewOperation.call({ id: bookingId, ...payload }),
    onSuccess: (data) => onSuccess(data, "Operation request reviewed"),
    onError: () => toast.error("Failed to review operation request"),
  });

  const approveStep = useMutation({
    mutationFn: ({
      stepId,
      requiredRole,
    }: {
      stepId: string;
      requiredRole: string;
    }) =>
      api.bookings.approveStep.call({
        id: bookingId,
        stepId,
        requiredRole,
      }),
    onSuccess: (data) => onSuccess(data, "Approval step completed"),
    onError: () => toast.error("Failed to approve step"),
  });

  const rejectStep = useMutation({
    mutationFn: ({
      stepId,
      reason,
    }: {
      stepId: string;
      reason: string;
    }) =>
      api.bookings.rejectStep.call({
        id: bookingId,
        stepId,
        reason,
      }),
    onSuccess: (data) => onSuccess(data, "Booking rejected at approval step"),
    onError: () => toast.error("Failed to reject step"),
  });

  const generateContract = useMutation({
    mutationFn: () => api.bookings.generateContract.call({ id: bookingId }),
    onSuccess: (data) => onSuccess(data, "Contract generated"),
    onError: () => toast.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: () => toast.error("Failed to sign contract"),
  });

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

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

  const complete = useMutation({
    mutationFn: () => api.bookings.complete.call({ id: bookingId }),
    onSuccess: (data) => onSuccess(data, "Booking completed"),
    onError: () => toast.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: () => toast.error("Failed to cancel booking"),
  });

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

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