// Provider-neutral mapping types. Pages import only these and <JobMap>; the
// active provider implementation lives under components/map/esri/.

export interface MapPoint {
  id: string;
  lat: number;
  lng: number;
  altitude: number | null;
  utilityType: string;
  fixType: string;
  sequence: number | null;
  recordedAt: string;
  // GPS quality
  hAccuracy: number | null;
  vAccuracy: number | null;
  satellites: number | null;
  hdop: number | null;
  // Locator receiver telemetry (all optional — depends on the instrument)
  depth: number | null;
  frequencyHz: number | null;
  currentMa: number | null;
  signalDb: number | null;
  gainDb: number | null;
  locateMode: string | null;
  phaseDeg: number | null;
  compassDeg: number | null;
  distortionPct: number | null;
}

export function pointSummary(p: MapPoint): string {
  const parts = [`${p.utilityType} · ${p.fixType}`];
  if (p.depth != null) parts.push(`depth ${p.depth}m`);
  if (p.frequencyHz != null)
    parts.push(p.frequencyHz >= 1000 ? `${p.frequencyHz / 1000}kHz` : `${p.frequencyHz}Hz`);
  if (p.currentMa != null) parts.push(`${p.currentMa}mA`);
  if (p.locateMode) parts.push(p.locateMode);
  return parts.join(' · ');
}

// Ordered [label, value] pairs for a full detail readout — only fields the
// point actually has are included, since instruments vary in what they report.
export function pointDetailRows(p: MapPoint): Array<[string, string]> {
  const rows: Array<[string, string]> = [
    ['Utility', p.utilityType],
    ['GPS fix', p.fixType],
    ['Recorded', new Date(p.recordedAt).toLocaleString()],
  ];
  if (p.sequence != null) rows.push(['Sequence', String(p.sequence)]);
  if (p.depth != null) rows.push(['Depth', `${p.depth} m`]);
  if (p.frequencyHz != null) {
    rows.push(['Frequency', p.frequencyHz >= 1000 ? `${p.frequencyHz / 1000} kHz` : `${p.frequencyHz} Hz`]);
  }
  if (p.currentMa != null) rows.push(['Current', `${p.currentMa} mA`]);
  if (p.signalDb != null) rows.push(['Signal', `${p.signalDb} dB`]);
  if (p.gainDb != null) rows.push(['Gain', `${p.gainDb} dB`]);
  if (p.locateMode) rows.push(['Locate mode', p.locateMode]);
  if (p.phaseDeg != null) rows.push(['Phase', `${p.phaseDeg}°`]);
  if (p.compassDeg != null) rows.push(['Compass', `${p.compassDeg}°`]);
  if (p.distortionPct != null) rows.push(['Distortion', `${p.distortionPct}%`]);
  if (p.altitude != null) rows.push(['Altitude', `${p.altitude} m`]);
  if (p.hAccuracy != null) rows.push(['Horiz. accuracy', `±${p.hAccuracy} m`]);
  if (p.vAccuracy != null) rows.push(['Vert. accuracy', `±${p.vAccuracy} m`]);
  if (p.satellites != null) rows.push(['Satellites', String(p.satellites)]);
  if (p.hdop != null) rows.push(['HDOP', String(p.hdop)]);
  rows.push(['Coordinates', `${p.lat.toFixed(7)}, ${p.lng.toFixed(7)}`]);
  return rows;
}

// A transmitter's current position, pushed live over the job's realtime
// channel. Never persisted as a LocatePoint — just the latest "where is it
// right now," replaced in place as new status updates arrive.
export interface LiveStatus {
  deviceId: string;
  serial: string;
  lat: number;
  lng: number;
  altitude: number | null;
  utilityType: string;
  fixType: string;
  hAccuracy: number | null;
  vAccuracy: number | null;
  satellites: number | null;
  hdop: number | null;
  depth: number | null;
  frequencyHz: number | null;
  currentMa: number | null;
  signalDb: number | null;
  gainDb: number | null;
  locateMode: string | null;
  phaseDeg: number | null;
  compassDeg: number | null;
  distortionPct: number | null;
  recordedAt: string;
}

export function liveStatusToMapPoint(s: LiveStatus): MapPoint {
  return { ...s, id: `live-${s.serial}`, sequence: null };
}

export interface JobMapProps {
  points: MapPoint[];
  // Live current position of a transmitter, shown as a distinct marker
  liveStatus?: LiveStatus | null;
  // Pan/zoom to fit all points whenever their count changes
  fitBounds?: boolean;
  heightPx?: number;
}

// APWA uniform color code for marking underground utilities
export const UTILITY_COLORS: Record<string, string> = {
  ELECTRIC: '#d32f2f', // red
  GAS: '#fbc02d', // yellow
  WATER: '#1976d2', // blue
  SEWER: '#388e3c', // green
  TELECOM: '#f57c00', // orange
  CATV: '#f57c00', // orange
  FIBER: '#f57c00', // orange
  STEAM: '#fbc02d', // yellow
  UNKNOWN: '#e91e8c', // pink (unknown/proposed)
};
