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

import { URL_CONSTANTS } from '@/constants/URLS';
import type {
  AllocationCriteria,
  AllocationPreviewResult,
  AllocationRule,
  ArrivalQueueItem,
  AutoLoadResult,
  AutoUnloadResult,
  FeePreview,
  FeeRule,
  InspectionAttachment,
  InspectionReport,
  InspectionReportPayload,
  SaveAllocationRulePayload,
  SaveFeeRulePayload,
  WarehouseFeeInvoice,
  WarehouseInvoiceFilter,
  PayInvoicePayload,
  BookingScheduleView,
  InventoryFilter,
  InventoryInquiryFilter,
  InventoryInquiryResult,
  InventoryMovement,
  LoadableWagon,
  LoadInventoryPayload,
  MoveInventoryPayload,
  ReceiveInventoryPayload,
  ReleaseOrderPayload,
  DeliverInventoryPayload,
  EligibleBooking,
  BulkReceivePayload,
  BulkReceiveResult,
  LoadPassedExportResult,
  BulkInspectPayload,
  BulkInspectResult,
  ReadyToLoadRow,
  BulkDispatchResult,
  ImportTrain,
  ImportTrainItem,
  ImportUnloadedItem,
  AutoUnloadArrivedResult,
  ReserveInventoryPayload,
  SaveWarehousePayload,
  SaveYardPayload,
  SaveZonePayload,
  Warehouse,
  WarehouseActivityLog,
  WarehouseDashboard,
  WarehouseFilter,
  WarehouseInventoryItem,
  WarehouseLoading,
  WarehouseYard,
  WarehouseZone,
} from '@/types/warehouse';

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

export const warehouseService = {
  // ── Warehouses ──────────────────────────────────────────────────────────
  list: (filter?: WarehouseFilter) =>
    apiClient.get<Warehouse[]>(URL_CONSTANTS.WAREHOUSES.BASE, {
      params: cleanParams(filter ?? {}),
    }),
  dashboard: () => 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 ────────────────────────────────────────────────────────────────
  listYards: (warehouseId: string) =>
    apiClient.get<WarehouseYard[]>(URL_CONSTANTS.WAREHOUSES.YARDS(warehouseId)),
  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)),
  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) =>
    apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.STORE(id)),
  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),
  deliver: (id: string, payload: DeliverInventoryPayload) =>
    apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.DELIVER(id), payload),

  // ── 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),
  loadPassedExport: () =>
    apiClient.post<LoadPassedExportResult>(URL_CONSTANTS.WAREHOUSE_INVENTORY.LOAD_PASSED_EXPORT, {}),
  bulkMarkInspected: (payload: BulkInspectPayload) =>
    apiClient.post<BulkInspectResult>(URL_CONSTANTS.WAREHOUSE_INVENTORY.BULK_MARK_INSPECTED, payload),
  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: (scheduleId: string) =>
    apiClient.post<AutoUnloadArrivedResult>(
      URL_CONSTANTS.WAREHOUSE_INVENTORY.IMPORT_AUTO_UNLOAD_ARRIVED,
      { scheduleId },
    ),
  importUnloadedQueue: () =>
    apiClient.get<ImportUnloadedItem[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.IMPORT_UNLOADED_QUEUE),
  importPickupReadyQueue: () =>
    apiClient.get<ImportUnloadedItem[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.IMPORT_PICKUP_READY_QUEUE),
  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),
  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) =>
    apiClient.get<FeePreview[]>(URL_CONSTANTS.WAREHOUSE_RULES.FEE_PREVIEW(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)),
  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) =>
    apiClient.post<WarehouseFeeInvoice>(URL_CONSTANTS.WAREHOUSE_INVOICES.GENERATE(inventoryId), { confirmZero }),
  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),
  gateClearance: (inventoryId: string) =>
    apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVOICES.GATE_CLEARANCE(inventoryId), {}),
};
