/**
 * @license
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * Leaflet map for the Dispatch cockpit — the live route map that replaces the
 * earlier gated placeholder. Plots each delivery's drop point as a numbered pin
 * (coloured per rider) and, when a rider/zone is focused, draws the planned stop
 * sequence as a dashed polyline. Uses OpenStreetMap tiles via react-leaflet.
 *
 * Coordinates come from the delivery rows (droplat/droplon, falling back to
 * deliverylat/deliverylong). Rows without coordinates are simply not plotted.
 * (Road-snapped routing + live rider GPS remain backend work — this draws the
 * planned order with straight segments, not fabricated GPS traces.)
 */

import React, { useEffect, useState } from 'react';
import { MapContainer, TileLayer, Marker, Polyline, useMap } from 'react-leaflet';
import { Bike, Mailbox, Utensils, MapPin, Map as MapIcon, Ruler, X } from 'lucide-react';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';

export interface MapPoint {
  id: string;
  lat: number;
  lon: number;
  step: number;
  color: string;
  title: string;
  subtitle?: string;
  status: string;
  /** Full delivery row, for the rich click popup. */
  raw: Record<string, unknown>;
}

// ── Popup helpers (replicated from nearle_console renderOrderPopupContent) ────────
const STATUS_HEX: Record<string, string> = {
  created: '#0ea5e9', processing: '#0ea5e9', pending: '#f59e0b', accepted: '#6366f1',
  arrived: '#06b6d4', picked: '#8b5cf6', active: '#14b8a6', skipped: '#f97316',
  delivered: '#22c55e', cancelled: '#ef4444',
};
function statusStyle(s: string) {
  const k = String(s || '').toLowerCase();
  const hex = STATUS_HEX[k] || '#64748b';
  return { bg: `${hex}1f`, fg: hex, label: k ? k.charAt(0).toUpperCase() + k.slice(1) : '—' };
}
function fmtTime(raw: unknown): string {
  const m = String(raw ?? '').match(/(\d{1,2}):(\d{2})/);
  return m ? `${m[1]}:${m[2]}` : '';
}
const POPUP_TIMELINE: Array<{ key: string; label: string; final?: boolean }> = [
  { key: 'assigntime', label: 'Assigned' },
  { key: 'acceptedtime', label: 'Accepted' },
  { key: 'arrivaltime', label: 'Arrived' },
  { key: 'pickuptime', label: 'Pickup' },
  { key: 'starttime', label: 'Started' },
  { key: 'deliverytime', label: 'Delivered', final: true },
];
const S = (v: unknown) => (v == null ? '' : String(v));

function PuDetail({ icon, label, value }: { icon: React.ReactNode; label: string; value: string }) {
  return (
    <div className="pu-detail">
      <div className="pu-detail-icon">{icon}</div>
      <div className="pu-detail-body">
        <div className="pu-detail-label">{label}</div>
        <div className="pu-detail-value" title={value}>{value}</div>
      </div>
    </div>
  );
}

/** The centered click popup — same structure/classes as the source console. */
function OrderPopup({ o, onClose }: { o: Record<string, unknown>; onClose: () => void }) {
  const st = S(o.orderstatus).toLowerCase();
  const ss = statusStyle(st);
  const rider = S(o.rider_name) || S(o.ridername) || S(o.username) || 'Unassigned';
  const customer = S(o.deliverycustomer) || S(o.customername);
  const pickup = S(o.pickupcustomer) || S(o.locationname) || S(o.pickuplocation);
  const drop = S(o.deliverysuburb) || S(o.deliveryaddress);
  const zone = S(o.zone_name);
  const riderId = o.rider_id || o.userid;
  const kms = o.kms;
  const actual = o.actualkms ?? o.cumulativekms;
  const hasTimeline = POPUP_TIMELINE.some((t) => fmtTime(o[t.key]));
  const hasDistance = (kms != null && kms !== '') || (actual != null && Number(actual) > 0);

  return (
    <div className="dispatch-popup-center" onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="dispatch-popup-card dispatch-popup">
        <button className="dispatch-popup-center-close" onClick={onClose} aria-label="Close">
          <X size={15} />
        </button>
        <div style={{ height: '100%', width: '100%' }}>
          <div className="pu-header">
            <div className="pu-header-top">
              <div className="pu-id">ORDER #{S(o.orderid) || S(o.deliveryid)}</div>
              {st && <span className="pu-status-chip" style={{ background: ss.bg, color: ss.fg }}>{ss.label}</span>}
            </div>
            <div className="pu-rider"><Bike size={13} /> <span>{rider}</span></div>
            {customer && <div className="pu-customer" title={customer}><Mailbox size={13} /><span>{customer}</span></div>}
            {o.deliveryid != null && <div className="pu-delivery-id">Delivery #{S(o.deliveryid)}</div>}
          </div>

          <div className="pu-body">
            {hasTimeline && (
              <div className="pu-section">
                <div className="pu-section-label">Timeline</div>
                <div className="pu-timeline">
                  {POPUP_TIMELINE.map((t) => {
                    const time = fmtTime(o[t.key]);
                    if (!time) return null;
                    return (
                      <div key={t.key} className={`pu-tl-row ${t.final ? 'delivered' : ''}`}>
                        <span className="pu-tl-dot" />
                        <span className="pu-tl-label">{t.label}</span>
                        <span className="pu-tl-time">{time}</span>
                      </div>
                    );
                  })}
                </div>
              </div>
            )}

            <div className="pu-section">
              <div className="pu-section-label">Details</div>
              <div className="pu-details-grid">
                {pickup && <PuDetail icon={<Utensils size={13} />} label="Pickup" value={pickup} />}
                {drop && <PuDetail icon={<MapPin size={13} />} label="Drop" value={drop} />}
                {zone && <PuDetail icon={<MapIcon size={13} />} label="Zone" value={zone} />}
                {riderId ? <PuDetail icon={<Bike size={13} />} label="Rider ID" value={`#${S(riderId)}`} /> : null}
              </div>

              {hasDistance && (
                <div className="pu-distance-row">
                  {kms != null && kms !== '' && (
                    <div className="pu-distance-chip">
                      <span className="pu-distance-icon"><Ruler size={12} /></span>
                      <span className="pu-distance-label">Planned</span>
                      <span className="pu-distance-value">{S(kms)} km</span>
                    </div>
                  )}
                  {actual != null && Number(actual) > 0 && (
                    <div className="pu-distance-chip">
                      <span className="pu-distance-icon"><Ruler size={12} /></span>
                      <span className="pu-distance-label">Actual</span>
                      <span className="pu-distance-value">{Number(actual).toFixed(2)} km</span>
                    </div>
                  )}
                </div>
              )}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

const COIMBATORE: [number, number] = [11.0168, 76.9558];

/**
 * Road-following route through the ordered waypoints via the public OSRM service.
 * Returns the snapped geometry as [lat, lon][] (Leaflet order), or null on failure
 * (caller then falls back to straight segments).
 */
async function fetchRoadRoute(waypoints: Array<[number, number]>, signal: AbortSignal): Promise<Array<[number, number]> | null> {
  if (waypoints.length < 2) return null;
  const path = waypoints.map(([la, lo]) => `${lo},${la}`).join(';'); // OSRM wants lon,lat
  const url = `https://router.project-osrm.org/route/v1/driving/${path}?overview=full&geometries=geojson`;
  try {
    const res = await fetch(url, { signal });
    if (!res.ok) return null;
    const data = await res.json();
    const coords = data?.routes?.[0]?.geometry?.coordinates;
    if (!Array.isArray(coords)) return null;
    return coords.map((c: [number, number]) => [c[1], c[0]] as [number, number]); // → lat,lon
  } catch {
    return null;
  }
}

/** Square hub/pickup marker. */
function hubIcon(): L.DivIcon {
  return L.divIcon({
    className: 'dispatch-hub',
    html: `<div style="width:26px;height:26px;border-radius:7px;background:#0f172a;color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:11px;border:2px solid #fff;box-shadow:0 2px 6px rgba(0,0,0,0.35)">H</div>`,
    iconSize: [26, 26],
    iconAnchor: [13, 13],
    popupAnchor: [0, -13],
  });
}

/** Numbered circular pin coloured to the point's rider/route. */
function pinIcon(step: number, color: string, dim: boolean): L.DivIcon {
  return L.divIcon({
    className: 'dispatch-pin',
    html: `<div style="width:28px;height:28px;border-radius:50%;background:${color};opacity:${dim ? 0.6 : 1};color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:11px;border:2px solid #fff;box-shadow:0 2px 6px rgba(0,0,0,0.35)">${step}</div>`,
    iconSize: [28, 28],
    iconAnchor: [14, 14],
    popupAnchor: [0, -14],
  });
}

/** Fit the view to the plotted points; invalidate size when the layout changes. */
function MapController({ points, resizeKey }: { points: MapPoint[]; resizeKey: unknown }) {
  const map = useMap();
  useEffect(() => {
    if (points.length === 0) return;
    if (points.length === 1) {
      map.setView([points[0].lat, points[0].lon], 14);
      return;
    }
    const bounds = L.latLngBounds(points.map((p) => [p.lat, p.lon] as [number, number]));
    map.fitBounds(bounds, { padding: [48, 48], maxZoom: 15 });
  }, [points, map]);
  useEffect(() => {
    const t = setTimeout(() => map.invalidateSize(), 220);
    return () => clearTimeout(t);
  }, [resizeKey, map]);
  return null;
}

export default function DispatchMap({
  points,
  route,
  routeColor = '#662582',
  start,
  resizeKey,
  animateNonce = 0,
}: {
  points: MapPoint[];
  route?: boolean;
  routeColor?: string;
  /** Optional pickup/hub the route starts from. */
  start?: [number, number] | null;
  resizeKey?: unknown;
  /** Increment to (re)play the route-draw animation. */
  animateNonce?: number;
}) {
  const [selected, setSelected] = useState<Record<string, unknown> | null>(null);
  // Straight segments through the ordered stops (hub → drops), used as the
  // fallback and shown instantly while the road route is fetched.
  const straight: Array<[number, number]> = [
    ...(start ? [start] : []),
    ...points.map((p) => [p.lat, p.lon] as [number, number]),
  ];

  // Road-snapped geometry from OSRM (null until it resolves / on failure).
  const [roadLine, setRoadLine] = useState<Array<[number, number]> | null>(null);
  useEffect(() => {
    if (!route || straight.length < 2) { setRoadLine(null); return; }
    const ctrl = new AbortController();
    fetchRoadRoute(straight, ctrl.signal).then((line) => setRoadLine(line));
    return () => ctrl.abort();
    // Re-fetch when the ordered coordinate set changes.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [route, JSON.stringify(straight)]);

  const line = roadLine ?? straight;

  // Route-draw animation: reveal the line progressively when animateNonce changes.
  const [drawn, setDrawn] = useState<number | null>(null);
  useEffect(() => {
    if (!animateNonce || !route || line.length < 2) return;
    let raf = 0;
    const t0 = performance.now();
    const dur = 2200;
    const total = line.length;
    const tick = (t: number) => {
      const p = Math.min(1, (t - t0) / dur);
      setDrawn(Math.max(2, Math.floor(p * total)));
      if (p < 1) raf = requestAnimationFrame(tick);
      else setDrawn(null);
    };
    raf = requestAnimationFrame(tick);
    return () => { cancelAnimationFrame(raf); setDrawn(null); };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [animateNonce]);
  const shownLine = drawn == null ? line : line.slice(0, drawn);

  return (
    <div style={{ position: 'relative', height: '100%', width: '100%' }}>
      <MapContainer center={COIMBATORE} zoom={12} scrollWheelZoom style={{ height: '100%', width: '100%' }} zoomControl>
        <TileLayer
          attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
        {route && shownLine.length > 1 && (
          <Polyline
            positions={shownLine}
            pathOptions={{ color: routeColor, weight: 4, opacity: 0.85, dashArray: roadLine ? undefined : '6 8' }}
          />
        )}
        {route && start && (
          <Marker position={start} icon={hubIcon()} eventHandlers={{ click: () => setSelected({ orderid: 'PICKUP', deliverycustomer: 'Pickup hub', pickupcustomer: 'Ragul Stores Hub' }) }} />
        )}
        {points.map((p) => (
          <Marker
            key={p.id}
            position={[p.lat, p.lon]}
            icon={pinIcon(p.step, p.color, p.status.toLowerCase() === 'cancelled')}
            eventHandlers={{ click: () => setSelected(p.raw) }}
          />
        ))}
        <MapController points={points} resizeKey={resizeKey} />
      </MapContainer>

      {selected && <OrderPopup o={selected} onClose={() => setSelected(null)} />}
    </div>
  );
}
