// Shared constants and pure helpers for the Dispatch page and its
// extracted sub-components (CompareDataPanel, etc.). Lives outside
// Dispatch.js so we don't create a circular import between the host
// component and the child views.

// Status palette — single source of truth for the status pill colors
// rendered on rider cards, order rows, step lists, and tooltips.
export const STATUS_STYLES = {
  created: { label: 'Created', bg: '#3b82f6', fg: '#fff' },
  pending: { label: 'Pending', bg: '#f59e0b', fg: '#fff' },
  accepted: { label: 'Accepted', bg: '#8b5cf6', fg: '#fff' },
  arrived: { label: 'Arrived', bg: '#ea580c', fg: '#fff' },
  picked: { label: 'Picked', bg: '#0ea5e9', fg: '#fff' },
  active: { label: 'Active', bg: '#0ea5e9', fg: '#fff' },
  delivered: { label: 'Delivered', bg: '#22c55e', fg: '#fff' },
  skipped: { label: 'Skipped', bg: '#94a3b8', fg: '#fff' },
  cancelled: { label: 'Cancelled', bg: '#ef4444', fg: '#fff' }
};

export const getStatusStyle = (status) =>
  STATUS_STYLES[String(status || '').toLowerCase()] || {
    label: status || 'Unknown',
    bg: '#64748b',
    fg: '#fff'
  };

// Order-status sets used for completion / skipped decisions across the
// rider list, the planned-route renderer, and the compare data panel.
export const FINAL_STATUSES = new Set(['delivered']);
export const SKIPPED_STATUSES = new Set(['cancelled', 'skipped']);

// Per-step palette — wider and more deliberately spaced than the rider
// palette so a 10-stop day reads as 10 distinct colors on the compare
// map's polylines + pins.
export const STEP_PALETTE = [
  '#2563eb', // blue-600
  '#dc2626', // red-600
  '#16a34a', // green-600
  '#ea580c', // orange-600
  '#9333ea', // purple-600
  '#0891b2', // cyan-600
  '#ca8a04', // yellow-600
  '#db2777', // pink-600
  '#0f766e', // teal-700
  '#7c3aed', // violet-600
  '#65a30d', // lime-600
  '#0284c7', // sky-600
  '#b91c1c', // red-700
  '#15803d', // green-700
  '#a16207', // yellow-700
  '#86198f'  // fuchsia-800
];

export const stepColor = (i) =>
  STEP_PALETTE[((i % STEP_PALETTE.length) + STEP_PALETTE.length) % STEP_PALETTE.length];

// Pure helper — converts 1, 2, 3, 21 → "1st", "2nd", "3rd", "21st". Used
// by the compare data panel for the route-sequence diff list ("Visited
// 4th · planned 2nd").
export const ordinal = (n) => {
  if (n == null) return '';
  const s = ['th', 'st', 'nd', 'rd'];
  const v = n % 100;
  return n + (s[(v - 20) % 10] || s[v] || s[0]);
};

// An order is "active" (currently in progress) when it's neither completed
// (delivered) nor skipped/cancelled. The Active view uses this to collapse a
// rider down to the single delivery they're working on right now.
export const isActiveDelivery = (o) => {
  const s = String(o?.orderstatus || '').toLowerCase();
  return s === 'active';
};

// A rider's single in-progress delivery: the first non-final, non-skipped
// stop in (trip, step) order. Returns null when the rider has nothing active
// (everything delivered/cancelled, or GPS-only with no orders).
export const getActiveOrder = (orders) => {
  if (!Array.isArray(orders) || !orders.length) return null;
  const sorted = [...orders].sort((a, b) => {
    const tA = a.trip_number || 1;
    const tB = b.trip_number || 1;
    if (tA !== tB) return tA - tB;
    return (a.step || 0) - (b.step || 0);
  });
  return sorted.find(isActiveDelivery) || null;
};
