import axios from 'axios';
import { OpenToast } from 'components/third-party/OpenToast';
import {
  getMilers,
  getMiler,
  getMilerSummary,
  getMilerLogs,
  notifyMiler,
  getAdminTenants,
  getAdminCustomers,
  getTenantLocations,
  getHubs,
  getBookings,
  getBooking,
  assignMilerToBooking,
  cancelBooking,
  bulkCancelBookings,
  updateConsignmentStatus,
  getAdminPricing,
  getPartners,
  getReports,
  getLocationsSummary,
  getDashboard,
  getProfile
} from 'pages/api/doormileApi';

// This file talks exclusively to api.doormile.com (see utils/doormileAxios.js /
// pages/api/doormileApi.js) — the old jupiter.nearle.app backend (REACT_APP_URL /
// REACT_APP_URL2) has been fully retired from this project. See
// express-console-api.md at the repo root for the endpoint reference.
//
// Several resources the old backend exposed (payment-mode types, tenant tab
// counts, rider check-in history, per-location/per-rider report breakdowns,
// rider login/checkout audit logs, live rider GPS/battery logs) have no
// equivalent in the new API. Those functions below return safe empty defaults
// (rather than throwing) so pages render an empty state instead of crashing —
// each is commented with why.

// The Deliveries page's STATUS_META/STATUS_TABS still use the old jupiter
// lifecycle keys (pending/accepted/arrived/picked/active/skipped/delivered/
// cancelled) for its tabs, chip counts, and row badges. The new booking
// status enum uses different strings entirely (Pending_Pickup,
// Converted_To_Consignment, Out_for_Delivery, ...) — only Pending_Pickup,
// Converted_To_Consignment (from a real sample) and Out_for_Delivery (named
// in express-console-api.md's CityGate note) are confirmed; the rest of this
// mapping is a best-effort guess. Unmapped statuses pass through lowercased,
// which the page's own fallback renders as an "unknown" badge rather than
// crashing. There's no confirmed equivalent for arrived/picked/skipped at
// all, so those tabs will show a 0 count until the real enum is confirmed.
const BOOKING_STATUS_TO_DELIVERY_STATUS = {
  pending_pickup: 'pending',
  converted_to_consignment: 'accepted',
  out_for_delivery: 'active',
  delivered: 'delivered',
  cancelled: 'cancelled'
};
const mapBookingStatusToDeliveryStatus = (status) => {
  const key = String(status || '').toLowerCase();
  return BOOKING_STATUS_TO_DELIVERY_STATUS[key] || key;
};

// Haversine straight-line distance in km — used wherever a resource carries
// lat/lng but no road-distance field (bookings, and by extension deliveries).
const haversineKm = (lat1, lon1, lat2, lon2) => {
  if (![lat1, lon1, lat2, lon2].every(Number.isFinite)) return undefined;
  const R = 6371;
  const toRad = (d) => (d * Math.PI) / 180;
  const dLat = toRad(lat2 - lat1);
  const dLon = toRad(lon2 - lon1);
  const a = Math.sin(dLat / 2) ** 2 + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2;
  return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
};

// ==============================|| getRiderPeriodicLogs ||============================== //
// Confirmed by jupiter2doormile.md as the direct replacement for jupiter's
// riderlogs table (Status: Done): GET /admin/milers/:id/logs. Field names on
// a log entry aren't documented anywhere (no example JSON in either
// reference doc) — this returns the most recent entry as-is and lets the
// page's own optional-chaining render whatever fields actually come back.
// Falls back to the miler record itself (which may carry a last-known
// position) if the logs call fails or returns nothing.
// Despite the parameter name (kept for caller compatibility), this must be
// a milerprofileid — /admin/milers/:id/* routes 404 on a plain userid
// (confirmed live).
export const getRiderPeriodicLogs = async (userid) => {
  if (!userid) return null;
  try {
    const logs = await getMilerLogs(userid, undefined, undefined, 1);
    const latest = Array.isArray(logs) ? logs[0] : logs;
    if (latest) return latest;
  } catch (err) {
    console.log('getRiderPeriodicLogs', err.message);
  }
  try {
    return (await getMiler(userid)) || null;
  } catch (err) {
    return null;
  }
};

// ==============================|| fetchAppLocations (zone/location picker) ||============================== //
// The new API has no "zones" resource — applocationid only exists as a field
// on Hubs. Derive a zone picker list from the distinct cities in GET /admin/hubs.
export const fetchAppLocations = async () => {
  try {
    const hubs = await getHubs();
    const seen = new Map();
    (hubs || []).forEach((hub) => {
      if (hub.applocationid != null && !seen.has(hub.applocationid)) {
        seen.set(hub.applocationid, { applocationid: hub.applocationid, locationname: hub.city || hub.hubname });
      }
    });
    return [...seen.values(), { locationname: 'All', applocationid: 0 }];
  } catch (err) {
    OpenToast(err.message, 'error', 2000);
    return [{ locationname: 'All', applocationid: 0 }];
  }
};

// ==============================|| fetchPercentageData (orders) ||============================== //
// Best-effort against /admin/reports — field names are our assumption since
// the doc only promises "counts + today's numbers", not an exact schema.
export const fetchPercentageData = async ({ queryKey }) => {
  const [, , startdate, enddate] = queryKey;
  const details = (await getReports(startdate, enddate)) || {};
  const total = details.total || 0;
  return {
    created: String(details.created || 0),
    uncoveredOrders: String(details.pending || 0),
    coveredOrders: String(details.delivered || 0),
    cancelled: String(details.cancelled || 0),
    percentage1: String(Math.round(((details.created || 0) / total) * 100) || 0),
    percentage2: String(Math.round(((details.pending || 0) / total) * 100) || 0),
    percentage3: String(Math.round(((details.delivered || 0) / total) * 100) || 0),
    percentage4: String(Math.round(((details.cancelled || 0) / total) * 100) || 0)
  };
};

// ===================================================== || getTenants || =====================================================

export const getTenants = async () => {
  const tenants = await getAdminTenants();
  return (tenants || []).map((val) => ({ ...val, label: val.tenantname }));
};

// ============================================= || gettenantlocations (branches) || =============================================
export const gettenantlocations = async (tenantId) => {
  try {
    return (await getTenantLocations(tenantId)) || [];
  } catch (err) {
    console.log('gettenantlocations', err);
    return [];
  }
};

// ==============================|| fetchorderscount (orders) ||============================== //

export const fetchorderscount = async ({ queryKey }) => {
  const [, , startdate, enddate] = queryKey;
  return (await getReports(startdate, enddate)) || {};
};

// ==============================|| fetchOrders (orders) ||============================== //
// Maps to /admin/bookings. The old endpoint's applocationid/tenantid/locationid
// filters and free-text `status` are not documented on this resource — pageno/
// pagesize are (see "Conventions" in express-console-api.md).
export const fetchOrders = async ({ pageParam = 1, queryKey }) => {
  const [, , , , , , rowsPerPage] = queryKey;
  const rows = (await getBookings(pageParam, rowsPerPage)) || [];
  return {
    rows,
    nextPage: rows.length === Number(rowsPerPage) ? pageParam + 1 : undefined
  };
};

// ==============================|| fetchPaymentType (orders) ||============================== //
// No payment-mode-types endpoint in the new API.
export const fetchPaymentType = async () => [];

// ==============================|| fetchRidersList (orders) ||============================== //

export const fetchRidersList = async () => {
  try {
    const milers = await getMilers();
    return (milers || []).map((val) => ({
      ...val,
      label: `${val.displayname || val.authname || ''} | ${val.contactno || ''}`
    }));
  } catch (err) {
    OpenToast(err.message, 'error', 2000);
    throw err;
  }
};

// ==============================|| createOptimisationDeliveries (orders) Arrange  the order ||============================== //
// AI dispatch optimiser — a separate solver service, left untouched by this
// migration (no equivalent exists in the new admin API).
export const createOptimisationDeliveries = async (deliveryData) => {
  const response = await axios.post(`https://routes.workolik.com/api/v1/optimization/createdeliveries`, deliveryData.deliveries);
  return response.data;
};
// ==============================|| reconcileSteps (Preview - validate rider/order step assignments) ||============================== //

export const reconcileSteps = async ({ riders }) => {
  const response = await axios.post(`https://routes.workolik.com/api/v1/optimization/reconcile-steps`, { riders });
  return response.data;
};

// ==============================|| fetchBatchEfficiency (Dispatch - Analysis view) ||============================== //

export const fetchBatchEfficiency = async ({ batch, tenantId }) => {
  const response = await axios.post(
    `https://routes.workolik.com/api/v1/batch/efficiency`,
    { batch, tenant_id: tenantId },
    { headers: { 'Content-Type': 'application/json' }, validateStatus: () => true }
  );
  return response.data;
};
// ==============================|| finalCreatedeliveries (orders) ||============================== //
// Final delivery commit — also part of the separate solver/optimiser pipeline,
// left untouched (still posts to jupiter.nearle.app directly, not via
// REACT_APP_URL, so this migration doesn't need to change it).
export const finalCreatedeliveries = async (deliveryData) => {
  const toInt = (v) => {
    const n = Number(v);
    return Number.isFinite(n) ? n : v;
  };
  const deliveries = (deliveryData.deliveries || []).map((d) => ({
    ...d,
    userid: toInt(d.userid),
    rider_id: toInt(d.rider_id)
  }));
  const response = await axios.post(`https://jupiter.nearle.app/live/api/v1/deliveries/createdeliveries`, deliveries);
  return response.data;
};
// ==============================|| createAutomationDeliveries (orders)  Auto rider Assign ||============================== //
// Also part of the optimiser pipeline (routes.workolik.com / routemate.workolik.com) — untouched.
export const createAutomationDeliveries = async (variables) => {
  const absentRiders = Array.isArray(variables.absent_riders) ? variables.absent_riders : [];
  const url =
    variables.selectedMode.value == 1
      ? `https://routes.workolik.com/api/v1/optimization/riderassign?hypertuning_params=${variables.hypertuning_params}`
      : `https://routemate.workolik.com/api/v1/optimization/riderassign?strategy=multi_trip`;
  const body =
    variables.selectedMode.value == 1
      ? { deliveries: variables.deliveries, absent_riders: absentRiders }
      : { ...(variables.data || {}), absent_riders: absentRiders };
  const response = await axios.post(url, body);
  return response.data;
};

// ==============================|| notifyRider (orders / deliveries) ||============================== //
// New API notifies by milerprofileid + title/message (server looks up the
// device token itself) instead of the caller passing an FCM token directly.
export const notifyRider = async (
  milerProfileId,
  title = 'DoormileXpress',
  message = 'Orders have been placed for delivery. Kindly accept and process deliveries.'
) => {
  if (!milerProfileId) {
    throw new Error('Invalid miler profile id');
  }
  return notifyMiler(milerProfileId, title, message);
};

// ==============================|| cancelOrder (orders) ||============================== //

export const cancelOrder = async (bookingId) => cancelBooking(bookingId);

// ==============================|| cancelMultipleOrder (orders) ||============================== //

export const cancelMultipleOrder = async (orderlist) => {
  const bookingIds = (orderlist || []).map((e) => e.bookingid ?? e.id);
  return bulkCancelBookings(bookingIds);
};

// ==============================|| fetchDeliveries (deliveries) ||============================== //
// GET /admin/consignments has zero documented response schema (see
// express-console-api.md — it's listed with no example body at all, unlike
// bookings). Rather than bind the deliveries table to an unknown shape, this
// builds the list from /admin/bookings (fully confirmed schema — see
// getBookings/fetchOrders in this same file) filtered to bookings that have
// actually been dispatched (assignedmileruserid or consignmentid set) — the
// Deliveries page is conceptually "orders that have moved past just being
// created", same underlying resource as the Orders page.
//
// Real consignment-only data (route step order, transit minutes, cumulative
// km, live delivery-leg status distinct from the booking's own status) has no
// confirmed field names and is NOT fabricated here — those cells render a
// "—" placeholder in the UI instead of invented numbers. If GET
// /admin/consignments' real shape is confirmed later, this is the function to
// extend with a join by booking.consignmentid.
//
// Each row is normalised onto the *old* jupiter field names the Deliveries
// page already reads (orderheaderid, deliverycustomer, ridername, etc.) so
// deliveries.js itself doesn't need a full rewrite — same compatibility-shim
// approach as fetchAllRiders' `{details}` wrapper.
export const fetchDeliveries = async ({ pageParam = 1, queryKey }) => {
  const [, , , , , , rowsPerPage] = queryKey;
  const [bookings, customers, milers, tenants] = await Promise.all([
    getBookings(pageParam, rowsPerPage),
    getAdminCustomers().catch(() => []),
    getMilers().catch(() => []),
    getAdminTenants().catch(() => [])
  ]);
  const customerMap = new Map((customers || []).map((c) => [c.appcustomerid ?? c.customerid ?? c.id, c]));
  const milerMap = new Map((milers || []).map((m) => [m.userid ?? m.milerid, m]));
  const tenantMap = new Map((tenants || []).map((t) => [t.tenantid, t]));

  const dispatched = (bookings || []).filter((b) => b.assignedmileruserid || b.consignmentid);

  const rows = dispatched.map((b) => {
    const customer = customerMap.get(b.appcustomerid);
    const miler = milerMap.get(b.assignedmileruserid);
    const tenant = tenantMap.get(b.tenantid);
    const charge = b.serviceoptions?.[0]?.estimatedprice;
    return {
      orderheaderid: b.bookingid,
      deliveryid: b.bookingid,
      orderid: b.bookingno || `#${b.bookingid}`,
      consignmentid: b.consignmentid,
      tenantname: tenant?.tenantname || '',
      tenantsuburb: '',
      applocation: '',
      tenantadress: tenant?.primaryemail || '',
      locationname: tenant?.tenantname || '',
      locationsuburb: '',
      pickupcustomer: '',
      pickupcontactno: '',
      Pickupaddress: b.pickupaddress || '',
      pickupaddress: b.pickupaddress || '',
      pickuplocation: b.pickupaddress || '',
      pickupsuburb: '',
      deliverycustomer: customer?.firstname || customer?.name || (b.appcustomerid ? `Customer #${b.appcustomerid}` : ''),
      deliverycontactno: customer?.phone || customer?.contactno || '',
      deliveryaddress: b.deliveryaddress || '',
      deliverylocation: b.deliveryaddress || '',
      deliverysuburb: '',
      ridername: miler?.displayname || (b.assignedmileruserid ? `Rider #${b.assignedmileruserid}` : ''),
      userid: b.assignedmileruserid,
      // GET /admin/milers/:id/notify (and block/assign-vehicle) key off
      // milerprofileid, not the userid stored on the booking — confirmed
      // live (a booking's assignedmileruserid matches a miler's `userid`
      // field, which 404s against /admin/milers/:id; milerprofileid is the
      // real primary key of that resource).
      milerprofileid: miler?.milerprofileid,
      ridercontact: miler?.phone || '',
      expecteddeliverytime: b.serviceoptions?.[0]?.estimateddeliveryat,
      // No route-plan data source (step order/transit time/cumulative km were
      // computed by the old jupiter backend from the dispatch optimiser's
      // output, not stored on a booking/consignment) — left undefined so the
      // UI's own "—" fallbacks render instead of a fabricated number.
      transitminutes: undefined,
      cumulativekms: undefined,
      step: undefined,
      // No road-distance field on a booking — approximated as a straight
      // line between pickup and delivery coordinates.
      kms: haversineKm(b.pickuplatitude, b.pickuplongitude, b.deliverylatitude, b.deliverylongitude),
      pickuplatitude: b.pickuplatitude,
      pickuplongitude: b.pickuplongitude,
      deliverylatitude: b.deliverylatitude,
      deliverylongitude: b.deliverylongitude,
      deliverycharges: charge,
      deliveryamt: charge,
      deliveryamount: charge,
      Quantity: b.parcels?.length || 0,
      quantity: b.parcels?.length || 0,
      collectionamt: undefined,
      notes: b.notes || '',
      deliverytype: customer ? 'B' : 'C',
      orderdate: b.createdat,
      deliverydate: b.serviceoptions?.[0]?.estimateddeliveryat || b.updatedat,
      assigntime: b.updatedat,
      orderstatus: mapBookingStatusToDeliveryStatus(b.status),
      droplat: b.deliverylatitude,
      droplon: b.deliverylongitude
    };
  });

  return {
    rows,
    nextPage: rows.length === Number(rowsPerPage) ? pageParam + 1 : undefined
  };
};

// Shared by fetchPercentageAPI/fetchCountAPI so the chip counts are derived
// from the exact same source (and status mapping) as fetchDeliveries' rows —
// counting against the separately-guessed /admin/dashboard shape produced
// numbers that didn't match what the table actually showed.
const getDeliveryStatusCounts = async () => {
  const bookings = (await getBookings(1, 1000)) || [];
  const dispatched = bookings.filter((b) => b.assignedmileruserid || b.consignmentid);
  const counts = { total: dispatched.length };
  dispatched.forEach((b) => {
    const status = mapBookingStatusToDeliveryStatus(b.status);
    counts[status] = (counts[status] || 0) + 1;
  });
  return counts;
};

// ==============================|| fetchPercentageAPI (deliveries) ||============================== //

export const fetchPercentageAPI = async () => {
  const data = await getDeliveryStatusCounts();
  return {
    coveredOrders: String(data.delivered || 0),
    cancelledOrders: String(data.cancelled || 0),
    uncoveredOrders: String(data.pending || 0),
    assignedOrders: String(data.accepted || 0),
    createdOrders: String(data.total || 0),
    closedOrders: String(data.delivered || 0),
    pickedOrders: String(data.picked || 0),
    percentage1: String(Math.round(((data.pending || 0) / (data.total || 1)) * 100) || 0),
    percentage2: String(Math.round(((data.accepted || 0) / (data.total || 1)) * 100) || 0),
    percentage3: String(Math.round(((data.picked || 0) / (data.total || 1)) * 100) || 0),
    percentage4: String(Math.round(((data.delivered || 0) / (data.total || 1)) * 100) || 0)
  };
};

// ==============================|| fetchCountAPI (deliveries) ||============================== //

export const fetchCountAPI = async () => {
  const data = await getDeliveryStatusCounts();
  return {
    total: data.total || 0,
    uncoveredLength: data.pending || 0,
    assignedLength: data.accepted || 0,
    arrivedLength: data.arrived || 0,
    pickedLength: data.picked || 0,
    activeLength: data.active || 0,
    coveredLength: data.delivered || 0,
    cancelLength: data.cancelled || 0,
    skippedLength: data.skipped || 0
  };
};

// ==============================|| cancelDeliveryAPI (deliveries) ||============================== //

// jupiter2doormile.md §4 confirms cancel is its own booking-level action —
// POST /admin/bookings/:id/cancel — not a consignment status PUT. cancelFeed
// isn't part of the documented cancel body; sent as a best-effort extra field
// rather than silently dropped, since it's unconfirmed whether the server
// persists it.
export const cancelDeliveryAPI = async (selectedRow, cancelFeed) =>
  cancelBooking(selectedRow.orderheaderid ?? selectedRow.deliveryid, { reason: cancelFeed });

// ==============================|| getorderdetails (deliveries) ||============================== //
export const getorderdetails = async (orderHeaderid) => getBooking(orderHeaderid);

// ==============================|| changeRiderAPI (deliveries) ||============================== //
// POST /admin/bookings/:id/assign-miler has no documented body — `milerid` as
// the JSON key is a guess (unverified, this is a write endpoint we didn't
// test live), but the VALUE must be the miler's milerprofileid regardless of
// key name: selectedRider comes straight from getMilers(), whose own .userid
// field is a different resource (confirmed live via GET /admin/milers/:id).
export const changeRiderAPI = async (selectedRider, selectedRow) =>
  assignMilerToBooking(selectedRow.orderheaderid ?? selectedRow.deliveryid, { milerid: selectedRider.milerprofileid });

// ==============================|| updateDeliveryAPI (deliveries) ||============================== //
// No amount/notes field exists on PUT /admin/consignments/:id/status — closest
// available write is a status update. Free-text amount/notes edits have no home
// in the new API yet.
export const updateDeliveryAPI = async (orderData) => updateConsignmentStatus(orderData.deliveryid ?? orderData.consignmentid, orderData);

// ==============================|| getalltenants (tenants) ||============================== //

export const getalltenants = async () => {
  try {
    return (await getAdminTenants()) || [];
  } catch (err) {
    const message = err.response?.data?.message || err.message || 'Something went wrong';
    OpenToast(message);
    return null;
  }
};
// ==============================|| gettenantsummary (tenants) ||============================== //
// No tenant-tab-counts endpoint in the new API.
export const gettenantsummary = async () => null;

// ==============================|| getpricinglist (tenants) ||============================== //

export const getpricinglist = async () => {
  try {
    return (await getAdminPricing()) || [];
  } catch (err) {
    const message = err.response?.data?.message || err.message || 'Something went wrong';
    OpenToast(message);
    return null;
  }
};
// ==============================|| getallpricing (clientPricing) ||============================== //
// This is the client-facing "Pricing" page (tenant pricing rules, GET
// /admin/pricing) — not GET /admin/doormile-pricing, which is Doormile's own
// internal banding with no tenant concept. Previously pointed at
// getDoormilePricing(), so the page's "Tenant"/"Tenants Priced" columns never
// had real data behind them.
export const getallpricing = async () => {
  try {
    return (await getAdminPricing()) || [];
  } catch (err) {
    const message = err.response?.data?.message || err.message || 'Something went wrong';
    OpenToast(message);
    return [];
  }
};

// ==============================|| fetchAllRiders (riders)  ||============================== //
export const fetchAllRiders = async () => {
  try {
    const milers = await getMilers();
    return { details: milers || [], nextPage: undefined };
  } catch (err) {
    console.log('fetchAllRiders err', err.message);
    return { details: [], nextPage: undefined };
  }
};
// ==============================|| getallridersummary (riders)  ||============================== //
export const getallridersummary = async () => {
  try {
    const milers = (await getMilers()) || [];
    // A miler has no `status` field — availabilitystatus is the real one
    // (confirmed live: Available/Assigned/On_Pickup/Offline). "Active" here
    // means not Offline, matching riders.js's own tab filter.
    const active = milers.filter((m) => String(m.availabilitystatus || '').toLowerCase() !== 'offline').length;
    return { total: milers.length, active, inactive: milers.length - active };
  } catch (err) {
    console.log('getallridersummary err', err.message);
    return { total: 0, active: 0, inactive: 0 };
  }
};

// ==============================|| fetchRiders (riders), active riders ||============================== //

export const fetchRiders = async () => {
  try {
    const milers = await getMilers();
    return { details: milers || [], nextPage: undefined };
  } catch (err) {
    console.log('fetchRiders err', err.message);
    return [];
  }
};

// ==============================|| getriderstatus (riders)||============================== //
// No check-in-history endpoint in the new API.
export const getriderstatus = async () => null;

// ==============================|| getreportsummary (orders summary)||============================== //
export const getreportsummary = async ({ queryKey }) => {
  const [, tenantid, locationid, startdate, enddate] = queryKey;
  return (await getReports(startdate, enddate, tenantid, locationid)) || {};
};

// ==============================|| getreportlocationsummary (orders summary)||============================== //
// Confirmed against jupiter2doormile.md (Status: Done) as the replacement for
// jupiter's getlocationsummary — GET /admin/locations/summary.
export const getreportlocationsummary = async ({ queryKey }) => {
  const [, tenantid, locationid, startdate, enddate] = queryKey;
  return (await getLocationsSummary(tenantid, locationid, startdate, enddate)) || [];
};

// ==============================|| fetchorderdetails (orders detail)||============================== //
export const fetchorderdetails = async ({ queryKey }) => {
  const [, , , page, rowsPerPage] = queryKey;
  const rows = (await getBookings(page, rowsPerPage)) || [];
  return rows.map((item, index) => ({ ...item, sno: index + 1 }));
};

// ==============================|| getriderbydelivery (orders detail)||============================== //
// No per-rider-delivery-trace endpoint in the new API.
export const getriderbydelivery = async () => [];

// ==============================|| fetchCount (orders detail)||============================== //

export const fetchCount = async () => (await getDashboard()) || {};

// ==============================|| fetchRidersSummary (riders summary)||============================== //
// No per-rider performance summary endpoint in the new API.
// Confirmed against jupiter2doormile.md (Status: Done) as the replacement
// for jupiter's getridersummary — GET /admin/milers/summary. Per-rider row
// field names aren't documented anywhere; this passes the response through
// as-is and lets the page's own rendering degrade gracefully on unknown keys.
export const fetchRidersSummary = async ({ queryKey }) => {
  const [, appId, startdate, enddate] = queryKey;
  const data = await getMilerSummary(appId || undefined, startdate, enddate);
  return Array.isArray(data) ? data : data ? [data] : [];
};

// ==============================|| fetchLocations (orders summary))||============================== //
export const fetchLocations = async () => {
  const partners = (await getPartners()) || [];
  return [...partners, { partnername: 'All', partnerid: -1 }];
};

// ==============================|| fetchRidersLogs (RiderLogs)||============================== //
// No rider login/checkout audit-log endpoint in the new API.
// Was a permanent [] stub ("no rider login/checkout audit-log endpoint") —
// that was true for the jupiter audit-log concept this was originally named
// after, but jupiter2doormile.md confirms (Status: Done) that
// GET /admin/milers/summary carries live position (currentlatitude/
// currentlongitude/lastpingat per that doc) for every rider at a zone. This
// feeds Dispatch.js's live map pins and "All Active Routes" view, which were
// both silently dead with the old stub.
//
// GET /admin/milers/summary confirmed live: { milerprofileid, userid,
// displayname, phone, availabilitystatus, defaultvehicletype, hubid,
// hubname, rating, onduty, dutystartedat, currentlatitude, currentlongitude,
// lastlocationupdatedat, lastpingat, assigned, accepted, rejected,
// completed, cancelled, delivered, riderkms, ridercharges } — no `status`,
// `contactno`, or current-order-id field exists at all. `id` is exposed as
// an alias of milerprofileid, which is what every /admin/milers/:id/* route
// (notify, block, assign-vehicle, logs) actually keys off — not userid.
export const fetchRidersLogs = async ({ queryKey } = {}) => {
  const [appId] = queryKey || [];
  try {
    const data = await getMilerSummary(appId || undefined);
    const riders = Array.isArray(data) ? data : data?.riders || data?.milers || [];
    return riders.map((r) => ({
      id: r.milerprofileid,
      milerprofileid: r.milerprofileid,
      userid: r.userid,
      username: r.displayname,
      status: r.availabilitystatus,
      contactno: r.phone,
      orderid: undefined,
      logdate: r.lastpingat ?? r.lastlocationupdatedat,
      latitude: r.currentlatitude,
      longitude: r.currentlongitude
    }));
  } catch (err) {
    console.log('fetchRidersLogs', err.message);
    return [];
  }
};

// ==============================|| getorders (Locations)||============================== //

export const fetchOrders1 = async ({ pageParam = 1, queryKey }) => {
  const [, , , , , , , rowsPerPage] = queryKey;
  const rows = (await getBookings(pageParam, rowsPerPage)) || [];
  return { details: rows, nextPage: rows.length === rowsPerPage ? pageParam + 1 : undefined };
};
// ==============================|| getusers (viewProfile)||============================== //

export const getusers = async () => {
  try {
    return (await getProfile()) || {};
  } catch (err) {
    console.log('getusers', err.message);
    return {};
  }
};
// ==============================|| getallriders (order)||============================== //

export const getallriders = async () => {
  try {
    return (await getMilers()) || [];
  } catch (err) {
    console.log('getallriders', err.message);
    return [];
  }
};
