import type { Freight } from '@edr/types';

import { api as apiClient } from '../auth/http';

import { URL_CONSTANTS } from '@/constants/URLS';
import type {
  ZoneOccupancy,
  TruckOnSite,
  WarehouseOpsStats,
  WarehouseThroughputPoint,
  WarehouseDwellStats,
  WarehouseCycleStats,
  WarehouseOnTimeStats,
  WarehouseGateStats,
  AccrualDashboardRow,
  AllocationCriteria,
  AllocationPreviewResult,
  AllocationRule,
  ArrivalQueueItem,
  AutoLoadResult,
  AutoUnloadResult,
  FeePreview,
  FeeRule,
  InspectionAttachment,
  InspectionReport,
  InspectionReportPayload,
  SaveAllocationRulePayload,
  SaveFeeRulePayload,
  WarehouseFeeInvoice,
  WarehouseInvoiceFilter,
  PayInvoicePayload,
  InitiateWarehouseInvoicePaymentPayload,
  WarehouseInvoicePaymentResponse,
  BookingScheduleView,
  InventoryFilter,
  InventoryInquiryFilter,
  InventoryInquiryResult,
  InventoryMovement,
  LoadableWagon,
  LoadInventoryPayload,
  MoveInventoryPayload,
  StoreInventoryPayload,
  ReceiveInventoryPayload,
  ReleaseOrderPayload,
  DeliverInventoryPayload,
  EligibleBooking,
  BulkReceivePayload,
  BulkReceiveResult,
  BulkInspectPayload,
  BulkInspectResult,
  ReadyToLoadRow,
  BulkDispatchResult,
  AutoUnloadExportDjiboutiResult,
  ExportTrain,
  ExportTrainItem,
  ImportTrain,
  ImportTrainItem,
  ImportUnloadedItem,
  AutoUnloadArrivedResult,
  ReserveInventoryPayload,
  SaveWarehousePayload,
  SaveYardPayload,
  SaveZonePayload,
  Warehouse,
  WarehouseActivityLog,
  WarehouseDashboard,
  WarehouseFacility,
  WarehouseFilter,
  WarehouseInventoryItem,
  WarehouseLoading,
  WarehouseYard,
  WarehouseZone,
} from '@/types/warehouse';

export type ContainerItemStage = 'PENDING' | 'RECEIVED' | 'GRN' | 'ASSIGNED' | 'LOADED' | 'LEFT' | 'DELIVERED';

export interface ContainerItem {
  containerNumber: string;
  goods: string | null;
  /** Container size, e.g. "20ft" / "40ft"; null for bulk. */
  containerSize: string | null;
  stage: ContainerItemStage;
  grnNumber: string | null;
  truckAssignmentId: string | null;
  truckPlate: string | null;
  truckArrived: boolean;
  truckLeft: boolean;
  /** Operator has loaded this container onto the truck (customer assignment alone is not "loaded"). */
  loaded: boolean;
  bookingReference: string | null;
  contractId: string | null;
  hasLastMile: boolean;
  handoverSigned: boolean;
}

/** A pre-dispatch EXPORT train that has inventory waiting to be loaded. */
export interface LoadableTrain {
  scheduleId: string;
  trainNumber: string | null;
  origin: string | null;
  destination: string | null;
  status: string;
  departureTime: string | null;
  readyCount: number;
  loadedCount: number;
}

/** A container/cargo inventory item assigned to a train, with its allocated wagon. */
export interface TrainLoadableItem {
  id: string;
  bookingId: string | null;
  bookingReference: string | null;
  customerName: string | null;
  containerNumber: string | null;
  cargoType: string | null;
  weight: number | null;
  grnNumber: string | null;
  inspectionStatus: string | null;
  status: string;
  wagonId: string | null;
  wagonNumber: string | null;
  sequenceNo: number | null;
  loadable: boolean;
}

export interface TrainLoadResult {
  loadedCount: number;
  skippedCount: number;
  results: { inventoryId: string; status: string; reason?: string }[];
}

const cleanParams = (params: object) =>
  Object.fromEntries(
    Object.entries(params).filter(([, value]) => value !== undefined && value !== '' && value !== null),
  );

/** An assigned EDR last-mile truck, shaped for the arrival/exit weighing prefill. */
export interface LastMileArrivalTruck {
  vehicleId: string;
  truckPlateNumber: string | null;
  trailerPlateNumber: string | null;
  driverName: string | null;
  driverLicense: string | null;
  driverPhone: string | null;
  truckType: string | null;
  containerNumber: string | null;
  arrivedAt: string | null;
  departedAt: string | null;
}

export const warehouseService = {
  /** Customer self-haul trucks assigned to a booking (portal multi-truck). */
  getCustomerTrucks: async (bookingId: string): Promise<Freight.ICustomerTruck[]> => {
    const { data } = await apiClient.get(`/bookings/${bookingId}/customer-trucks`);
    return data?.data ?? data ?? [];
  },

  /** Assigned EDR last-mile trucks for a booking (arrival/exit weighing prefill). */
  getLastMileTrucks: async (bookingId: string): Promise<LastMileArrivalTruck[]> => {
    const { data } = await apiClient.get(`/last-mile/booking/${bookingId}/arrival-trucks`);
    return data?.data ?? data ?? [];
  },

  /** Per-container/bulk items of a booking with lifecycle stage + refs. */
  getContainerItems: async (bookingId: string): Promise<ContainerItem[]> => {
    const { data } = await apiClient.get(
      `/warehouse-inventory/bookings/${bookingId}/container-items`,
    );
    return data?.data ?? data ?? [];
  },

  /** Ask the customer to sign the booking's handover (creates one if none, then notifies). */
  requestHandoverSignature: async (
    bookingId: string,
  ): Promise<{ notified: boolean; reference: string | null; alreadySigned: boolean }> => {
    const { data } = await apiClient.post(
      `/warehouse-inventory/bookings/${bookingId}/request-handover-signature`,
    );
    return data?.data ?? data;
  },

  /** A booking's containers with VGM cargo weight (tonnes) for exit weighing. */
  getContainerWeights: async (
    bookingId: string,
  ): Promise<Array<{ containerNumber: string; weightTons: number }>> => {
    const { data } = await apiClient.get(
      `/warehouse-inventory/bookings/${bookingId}/container-weights`,
    );
    return data?.data ?? data ?? [];
  },

  /** Booking container numbers not yet loaded onto any truck. */
  getLoadableContainers: async (bookingId: string): Promise<string[]> => {
    const { data } = await apiClient.get(
      `/bookings/${bookingId}/customer-trucks/loadable-containers`,
    );
    return data?.data ?? data ?? [];
  },

  /** Truck_dispatch: load selected containers onto a truck (after arrival). */
  loadTruck: async (
    bookingId: string,
    assignmentId: string,
    containerNumbers: string[],
  ): Promise<Freight.ICustomerTruck[]> => {
    const { data } = await apiClient.post(
      `/bookings/${bookingId}/customer-trucks/${assignmentId}/load`,
      { containerNumbers },
    );
    return data?.data ?? data ?? [];
  },

  // ── Load to Train ─────────────────────────────────────────────────────────
  /** Pre-dispatch EXPORT trains with inventory waiting to be loaded. */
  getLoadableTrains: async (): Promise<LoadableTrain[]> => {
    const { data } = await apiClient.get('/warehouse-inventory/loadable-trains');
    return data?.data ?? data ?? [];
  },

  /** Container/cargo items assigned to a train, with allocated wagon + stage. */
  getTrainLoadableItems: async (scheduleId: string): Promise<TrainLoadableItem[]> => {
    const { data } = await apiClient.get(
      `/warehouse-inventory/train/${scheduleId}/loadable-items`,
    );
    return data?.data ?? data ?? [];
  },

  /** Load selected inventory items onto their allocated wagons for a train. */
  loadItemsOntoTrain: async (
    scheduleId: string,
    inventoryIds: string[],
  ): Promise<TrainLoadResult> => {
    const { data } = await apiClient.post(
      `/warehouse-inventory/train/${scheduleId}/load`,
      { inventoryIds },
    );
    return data?.data ?? data ?? { loadedCount: 0, skippedCount: 0, results: [] };
  },

  // ── Warehouses ──────────────────────────────────────────────────────────
  list: (filter?: WarehouseFilter) =>
    apiClient.get<Warehouse[]>(URL_CONSTANTS.WAREHOUSES.BASE, {
      params: cleanParams(filter ?? {}),
    }),
  dashboard: () => apiClient.get<WarehouseDashboard>(URL_CONSTANTS.WAREHOUSES.DASHBOARD),
  getDashboardSummary: (_filter?: InventoryFilter) =>
    apiClient.get<WarehouseDashboard>(URL_CONSTANTS.WAREHOUSES.DASHBOARD),
  getById: (id: string) => apiClient.get<Warehouse>(URL_CONSTANTS.WAREHOUSES.BY_ID(id)),
  create: (payload: SaveWarehousePayload) =>
    apiClient.post<Warehouse>(URL_CONSTANTS.WAREHOUSES.BASE, payload),
  update: (id: string, payload: Partial<SaveWarehousePayload>) =>
    apiClient.patch<Warehouse>(URL_CONSTANTS.WAREHOUSES.BY_ID(id), payload),
  // Yards list now returns the standard paginated envelope ({ items, meta }).
  listFacilities: () =>
    apiClient.get<{ items: WarehouseFacility[] }>(URL_CONSTANTS.RULE_ENGINE.YARDS, {
      params: { pageSize: 100 },
    }),

  // ── Yards ────────────────────────────────────────────────────────────────
  listYards: (warehouseId: string) =>
    apiClient.get<WarehouseYard[]>(URL_CONSTANTS.WAREHOUSES.YARDS(warehouseId)),
  listAllYards: () => apiClient.get<WarehouseYard[]>(URL_CONSTANTS.WAREHOUSE_YARDS.BASE),
  createYard: (warehouseId: string, payload: SaveYardPayload) =>
    apiClient.post<WarehouseYard>(URL_CONSTANTS.WAREHOUSES.YARDS(warehouseId), payload),
  getYard: (id: string) => apiClient.get<WarehouseYard>(URL_CONSTANTS.WAREHOUSE_YARDS.BY_ID(id)),
  updateYard: (id: string, payload: Partial<SaveYardPayload>) =>
    apiClient.patch<WarehouseYard>(URL_CONSTANTS.WAREHOUSE_YARDS.BY_ID(id), payload),

  // ── Zones ──────────────────────────────────────────────────────────────
  listZones: (yardId: string) =>
    apiClient.get<WarehouseZone[]>(URL_CONSTANTS.WAREHOUSE_YARDS.ZONES(yardId)),
  listAllZones: () => apiClient.get<WarehouseZone[]>(URL_CONSTANTS.WAREHOUSE_ZONES.BASE),
  createZone: (yardId: string, payload: SaveZonePayload) =>
    apiClient.post<WarehouseZone>(URL_CONSTANTS.WAREHOUSE_YARDS.ZONES(yardId), payload),
  getZone: (id: string) => apiClient.get<WarehouseZone>(URL_CONSTANTS.WAREHOUSE_ZONES.BY_ID(id)),
  updateZone: (id: string, payload: Partial<SaveZonePayload>) =>
    apiClient.patch<WarehouseZone>(URL_CONSTANTS.WAREHOUSE_ZONES.BY_ID(id), payload),

  // ── Inventory ──────────────────────────────────────────────────────────
  listInventory: (filter?: InventoryFilter) =>
    apiClient.get<WarehouseInventoryItem[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.BASE, {
      params: cleanParams(filter ?? {}),
    }),
  receiveInventory: (payload: ReceiveInventoryPayload) =>
    apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.RECEIVE, payload),
  listReadyForLoading: (filter?: InventoryFilter) =>
    apiClient.get<WarehouseInventoryItem[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.READY_FOR_LOADING, {
      params: cleanParams(filter ?? {}),
    }),
  inquiry: (filter: InventoryInquiryFilter) =>
    apiClient.get<InventoryInquiryResult[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.INQUIRY, {
      params: cleanParams(filter ?? {}),
    }),

  // ── Lifecycle (Batch 2) ──────────────────────────────────────────────────
  store: (id: string, payload?: StoreInventoryPayload) =>
    apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.STORE(id), payload),
  reserve: (payload: ReserveInventoryPayload) =>
    apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.RESERVE, payload),
  markReadyForLoading: (id: string) =>
    apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.MARK_READY(id)),
  load: (id: string, payload: LoadInventoryPayload) =>
    apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.LOAD(id), payload),
  dispatch: (id: string) =>
    apiClient.patch<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.DISPATCH(id)),

  // ── Import branch (READY_FOR_PICKUP → DELIVERED) ─────────────────────────
  markReadyForPickup: (id: string) =>
    apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.MARK_READY_PICKUP(id)),
  release: (id: string, payload: ReleaseOrderPayload) =>
    apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.RELEASE(id), payload),
  downloadReleaseDocument: (id: string) =>
    apiClient.get<Blob>(URL_CONSTANTS.WAREHOUSE_INVENTORY.RELEASE_DOCUMENT(id), {
      responseType: 'blob',
    }),
  downloadGrnDocument: (id: string) =>
    apiClient.get<Blob>(URL_CONSTANTS.WAREHOUSE_INVENTORY.GRN_DOCUMENT(id), {
      responseType: 'blob',
    }),
  downloadHandoverDocument: (id: string) =>
    apiClient.get<Blob>(URL_CONSTANTS.WAREHOUSE_INVENTORY.HANDOVER_DOCUMENT(id), {
      responseType: 'blob',
    }),
  /** Per-truck exit paper PDF (containers loaded on one customer truck). */
  downloadTruckExitPaper: (assignmentId: string) =>
    apiClient.get<Blob>(`/warehouse-inventory/customer-truck-exit-paper/${assignmentId}`, {
      responseType: 'blob',
    }),
  /** Per-truck exit paper PDF for an EDR last-mile truck. */
  downloadEdrTruckExitPaper: (assignmentId: string) =>
    apiClient.get<Blob>(`/warehouse-inventory/edr-truck-exit-paper/${assignmentId}`, {
      responseType: 'blob',
    }),
  deliver: (id: string, payload: DeliverInventoryPayload) =>
    apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.DELIVER(id), payload),

  /** Post-unloading Yes/No — Yes makes the double-handling fee rule bill this booking. */
  setDoubleHandling: (bookingId: string, doubleHandling: boolean) =>
    apiClient.patch<{ bookingId: string; doubleHandling: boolean; setAt: string }>(
      `/warehouse-inventory/bookings/${bookingId}/double-handling`,
      { doubleHandling },
    ),

  // ── Receive (Import/Export bulk) ─────────────────────────────────────────
  eligibleBookings: (direction?: 'IMPORT' | 'EXPORT') =>
    apiClient.get<EligibleBooking[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.ELIGIBLE_BOOKINGS(direction)),
  receiveBulk: (payload: BulkReceivePayload) =>
    apiClient.post<BulkReceiveResult>(URL_CONSTANTS.WAREHOUSE_INVENTORY.RECEIVE_BULK, payload),
  bulkMarkInspected: (payload: BulkInspectPayload) =>
    apiClient.post<BulkInspectResult>(URL_CONSTANTS.WAREHOUSE_INVENTORY.BULK_MARK_INSPECTED, payload),
  receivedExport: () =>
    apiClient.get<ReadyToLoadRow[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.RECEIVED_EXPORT),
  readyToLoadExport: () =>
    apiClient.get<ReadyToLoadRow[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.READY_TO_LOAD_EXPORT),
  loadedExport: () =>
    apiClient.get<ReadyToLoadRow[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.LOADED_EXPORT),
  bulkDispatchExport: (inventoryIds: string[]) =>
    apiClient.post<BulkDispatchResult>(URL_CONSTANTS.WAREHOUSE_INVENTORY.BULK_DISPATCH_EXPORT, {
      inventoryIds,
    }),
  importArriveQueue: () =>
    apiClient.get<ImportTrain[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.IMPORT_ARRIVE_QUEUE),
  importTrainItems: (scheduleId: string) =>
    apiClient.get<ImportTrainItem[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.IMPORT_TRAIN_ITEMS(scheduleId)),
  autoUnloadArrivedBookings: (payload: {
    scheduleId: string;
    warehouseId?: string;
    assignments?: { bookingId: string; warehouseId: string; yardId: string; zoneId: string }[];
  }) =>
    apiClient.post<AutoUnloadArrivedResult>(
      URL_CONSTANTS.WAREHOUSE_INVENTORY.IMPORT_AUTO_UNLOAD_ARRIVED,
      payload,
    ),
  importUnloadedQueue: () =>
    apiClient.get<ImportUnloadedItem[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.IMPORT_UNLOADED_QUEUE),
  importPickupReadyQueue: () =>
    apiClient.get<ImportUnloadedItem[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.IMPORT_PICKUP_READY_QUEUE),
  exportDjiboutiArrivalQueue: () =>
    apiClient.get<ExportTrain[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.EXPORT_DJIBOUTI_ARRIVAL_QUEUE),
  exportDjiboutiTrainItems: (scheduleId: string) =>
    apiClient.get<ExportTrainItem[]>(
      URL_CONSTANTS.WAREHOUSE_INVENTORY.EXPORT_DJIBOUTI_TRAIN_ITEMS(scheduleId),
    ),
  autoUnloadExportAtDjibouti: (scheduleId: string) =>
    apiClient.post<AutoUnloadExportDjiboutiResult>(
      URL_CONSTANTS.WAREHOUSE_INVENTORY.EXPORT_AUTO_UNLOAD_AT_DJIBOUTI,
      { scheduleId },
    ),
  move: (id: string, payload: MoveInventoryPayload) =>
    apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.MOVE(id), payload),
  movements: (id: string) =>
    apiClient.get<InventoryMovement[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.MOVEMENTS(id)),
  activity: (id: string) =>
    apiClient.get<WarehouseActivityLog[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.ACTIVITY(id)),

  // ── Loading (Batch 3) ─────────────────────────────────────────────────────
  loadableWagons: () =>
    apiClient.get<LoadableWagon[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.LOADABLE_WAGONS),
  bookingSchedule: (bookingId: string) =>
    apiClient.get<BookingScheduleView>(URL_CONSTANTS.WAREHOUSE_INVENTORY.BOOKING_SCHEDULE(bookingId)),
  inventoryLoadings: (id: string) =>
    apiClient.get<WarehouseLoading[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.LOADINGS(id)),
  loadings: (params?: { bookingId?: string; wagonId?: string }) =>
    apiClient.get<WarehouseLoading[]>(URL_CONSTANTS.WAREHOUSE_LOADINGS.BASE, {
      params: cleanParams(params ?? {}),
    }),

  // ── Batch 4.5: Arrival / Unload / Load automation ──────────────────────────
  arrivalQueue: () =>
    apiClient.get<ArrivalQueueItem[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.ARRIVAL_QUEUE),
  zoneOccupancy: (yardId?: string) =>
    apiClient.get<ZoneOccupancy[]>(
      URL_CONSTANTS.WAREHOUSE_INVENTORY.ZONE_OCCUPANCY(yardId),
    ),
  opsStats: () =>
    apiClient.get<WarehouseOpsStats>(URL_CONSTANTS.WAREHOUSE_INVENTORY.OPS_STATS),
  /** Trucks inside the yard right now — the list behind the trucksOnSite figure. */
  trucksOnSite: () =>
    apiClient.get<TruckOnSite[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.TRUCKS_ON_SITE),
  throughput: (granularity: 'week' | 'month' | 'year') =>
    apiClient.get<WarehouseThroughputPoint[]>(
      URL_CONSTANTS.WAREHOUSE_INVENTORY.THROUGHPUT(granularity),
    ),
  dwellStats: () =>
    apiClient.get<WarehouseDwellStats>(URL_CONSTANTS.WAREHOUSE_INVENTORY.DWELL_STATS),
  cycleStats: () =>
    apiClient.get<WarehouseCycleStats>(URL_CONSTANTS.WAREHOUSE_INVENTORY.CYCLE_STATS),
  gateStats: () =>
    apiClient.get<WarehouseGateStats>(URL_CONSTANTS.WAREHOUSE_INVENTORY.GATE_STATS),
  autoUnloadArrived: () =>
    apiClient.post<AutoUnloadResult>(URL_CONSTANTS.WAREHOUSE_INVENTORY.AUTO_UNLOAD_ARRIVED),
  autoLoadReady: () =>
    apiClient.post<AutoLoadResult>(URL_CONSTANTS.WAREHOUSE_INVENTORY.AUTO_LOAD_READY),
  unloadBooking: (bookingId: string, payload?: Record<string, unknown>) =>
    apiClient.post<WarehouseInventoryItem>(
      URL_CONSTANTS.WAREHOUSE_INVENTORY.UNLOAD_BOOKING(bookingId),
      payload ?? {},
    ),

  // ── Batch 4.5: Inspection reports ──────────────────────────────────────────
  listInspectionReports: (inventoryId: string) =>
    apiClient.get<InspectionReport[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.INSPECTION_REPORTS(inventoryId)),
  createInspectionReport: (inventoryId: string, payload: InspectionReportPayload) =>
    apiClient.post<InspectionReport>(
      URL_CONSTANTS.WAREHOUSE_INVENTORY.INSPECTION_REPORTS(inventoryId),
      payload,
    ),
  getInspectionReport: (id: string) =>
    apiClient.get<InspectionReport>(URL_CONSTANTS.WAREHOUSE_INSPECTION.BY_ID(id)),
  uploadInspectionAttachments: (id: string, files: File[]) => {
    const form = new FormData();
    files.forEach((file) => form.append('files', file));
    return apiClient.post<InspectionAttachment[]>(
      URL_CONSTANTS.WAREHOUSE_INSPECTION.ATTACHMENTS(id),
      form,
      { headers: { 'Content-Type': 'multipart/form-data' } },
    );
  },

  // ── Batch 5: Allocation + Fee rules / previews ─────────────────────────────
  listAllocationRules: () =>
    apiClient.get<AllocationRule[]>(URL_CONSTANTS.WAREHOUSE_RULES.ALLOCATION),
  createAllocationRule: (payload: SaveAllocationRulePayload) =>
    apiClient.post<AllocationRule>(URL_CONSTANTS.WAREHOUSE_RULES.ALLOCATION, payload),
  updateAllocationRule: (id: string, payload: Partial<SaveAllocationRulePayload>) =>
    apiClient.patch<AllocationRule>(URL_CONSTANTS.WAREHOUSE_RULES.ALLOCATION_BY_ID(id), payload),
  deleteAllocationRule: (id: string) =>
    apiClient.delete(URL_CONSTANTS.WAREHOUSE_RULES.ALLOCATION_BY_ID(id)),
  previewAllocation: (criteria: AllocationCriteria) =>
    apiClient.post<AllocationPreviewResult | null>(URL_CONSTANTS.WAREHOUSE_RULES.ALLOCATION_PREVIEW, criteria),

  listFeeRules: () => apiClient.get<FeeRule[]>(URL_CONSTANTS.WAREHOUSE_RULES.FEES),
  createFeeRule: (payload: SaveFeeRulePayload) =>
    apiClient.post<FeeRule>(URL_CONSTANTS.WAREHOUSE_RULES.FEES, payload),
  updateFeeRule: (id: string, payload: Partial<SaveFeeRulePayload>) =>
    apiClient.patch<FeeRule>(URL_CONSTANTS.WAREHOUSE_RULES.FEES_BY_ID(id), payload),
  deleteFeeRule: (id: string) => apiClient.delete(URL_CONSTANTS.WAREHOUSE_RULES.FEES_BY_ID(id)),
  feePreview: (inventoryId: string, billingCurrency?: 'ETB' | 'USD') =>
    apiClient.get<FeePreview[]>(URL_CONSTANTS.WAREHOUSE_RULES.FEE_PREVIEW(inventoryId), {
      params: cleanParams({ billingCurrency }),
    }),
  accrualDashboard: (billingCurrency?: 'ETB' | 'USD') =>
    apiClient.get<AccrualDashboardRow[]>(URL_CONSTANTS.WAREHOUSE_RULES.ACCRUAL_DASHBOARD, {
      params: cleanParams({ billingCurrency }),
    }),
  onTimeDispatch: () =>
    apiClient.get<WarehouseOnTimeStats>(URL_CONSTANTS.WAREHOUSE_RULES.ON_TIME_DISPATCH),
  acknowledgeAccrual: (inventoryId: string, body: { snoozeDays?: number; note?: string } = {}) =>
    apiClient.post(URL_CONSTANTS.WAREHOUSE_RULES.ACCRUAL_ACK(inventoryId), body),
  unacknowledgeAccrual: (inventoryId: string) =>
    apiClient.delete(URL_CONSTANTS.WAREHOUSE_RULES.ACCRUAL_ACK(inventoryId)),

  // ── Batch 6: Warehouse fee invoices ────────────────────────────────────────
  listInvoices: (filter?: WarehouseInvoiceFilter) =>
    apiClient.get<WarehouseFeeInvoice[]>(URL_CONSTANTS.WAREHOUSE_INVOICES.BASE, {
      params: cleanParams(filter ?? {}),
    }),
  getInvoice: (id: string) =>
    apiClient.get<WarehouseFeeInvoice>(URL_CONSTANTS.WAREHOUSE_INVOICES.BY_ID(id)),
  downloadInvoiceDocument: (id: string) =>
    apiClient.get<Blob>(URL_CONSTANTS.WAREHOUSE_INVOICES.DOCUMENT(id), {
      responseType: 'blob',
    }),
  downloadInvoiceReceipt: (id: string) =>
    apiClient.get<Blob>(URL_CONSTANTS.WAREHOUSE_INVOICES.RECEIPT(id), {
      responseType: 'blob',
    }),
  invoicesForInventory: (inventoryId: string) =>
    apiClient.get<WarehouseFeeInvoice[]>(URL_CONSTANTS.WAREHOUSE_INVOICES.FOR_INVENTORY(inventoryId)),
  invoicesForBooking: (bookingId: string) =>
    apiClient.get<WarehouseFeeInvoice[]>(URL_CONSTANTS.WAREHOUSE_INVOICES.FOR_BOOKING(bookingId)),
  generateInvoice: (inventoryId: string, confirmZero = false, billingCurrency?: 'ETB' | 'USD') =>
    apiClient.post<WarehouseFeeInvoice>(URL_CONSTANTS.WAREHOUSE_INVOICES.GENERATE(inventoryId), {
      confirmZero,
      billingCurrency,
    }),
  cancelInvoice: (id: string) =>
    apiClient.patch<WarehouseFeeInvoice>(URL_CONSTANTS.WAREHOUSE_INVOICES.CANCEL(id)),
  payInvoice: (id: string, payload: PayInvoicePayload) =>
    apiClient.post<WarehouseFeeInvoice>(URL_CONSTANTS.WAREHOUSE_INVOICES.PAY(id), payload),
  payInvoiceOnline: (id: string, payload: InitiateWarehouseInvoicePaymentPayload) =>
    apiClient.post<WarehouseInvoicePaymentResponse>(URL_CONSTANTS.WAREHOUSE_INVOICES.PAY_ONLINE(id), payload),
  gateClearance: (inventoryId: string) =>
    apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVOICES.GATE_CLEARANCE(inventoryId), {}),
};
