import React, { useEffect, useMemo, useRef, useState } from 'react';
import { GoogleMap, Polyline, Marker, InfoWindow, useJsApiLoader } from '@react-google-maps/api';
import { Box, IconButton, Stack, Typography, CircularProgress } from '@mui/material';
import { MdClose, MdRoute } from 'react-icons/md';

const containerStyle = { width: '100%', height: '100%' };

// Renders a single rider's PLANNED route for the date range chosen on the
// Riders Summary page. `details` is an ordered array of waypoints (sorted by
// the planning step number) shaped as:
//   { step, orderid, deliveryid, customer, address,
//     dropLat, dropLng, pickLat, pickLng, expectedTime }
// `dropLat/dropLng` are required; pickup coords are optional and rendered as
// faded pre-stops if present.
export default function RidersRoutes({ details, loading, riderName, dateRange, onClose }) {
  const mapRef = useRef(null);
  const [focusedStep, setFocusedStep] = useState(null);
  const [routePath, setRoutePath] = useState([]);
  const [routeLoading, setRouteLoading] = useState(false);

  const { isLoaded } = useJsApiLoader({
    googleMapsApiKey: process.env.REACT_APP_GOOGLE_MAPS_KEY
  });

  // Step-pin coordinates in planning order — what the polyline connects.
  const dropPath = useMemo(
    () => (details || []).map((d) => ({ lat: d.dropLat, lng: d.dropLng })),
    [details]
  );

  // Auto-fit map bounds to the full planned path once the map and data are
  // both ready. Re-runs whenever the route changes (different rider / date).
  useEffect(() => {
    if (!isLoaded || !mapRef.current || dropPath.length === 0) return;
    const bounds = new window.google.maps.LatLngBounds();
    dropPath.forEach((p) => bounds.extend(p));
    mapRef.current.fitBounds(bounds, 48);
  }, [isLoaded, dropPath]);

  // Resolve the rider's planned waypoints into an actual road-following path
  // via the Directions API. Without this, the polyline would cut across
  // buildings / aerial lines — operators have no way to read the real route.
  // Directions has a 25-waypoint limit per request, so we chunk and stitch.
  useEffect(() => {
    if (!isLoaded || dropPath.length < 2) {
      setRoutePath([]);
      return;
    }
    let cancelled = false;
    const ds = new window.google.maps.DirectionsService();
    const MAX_WPS = 23; // origin + 23 waypoints + destination = 25 stops/chunk

    const fetchSegment = (origin, destination, waypoints) =>
      new Promise((resolve, reject) => {
        ds.route(
          {
            origin,
            destination,
            waypoints: waypoints.map((p) => ({ location: p, stopover: true })),
            travelMode: window.google.maps.TravelMode.DRIVING
          },
          (result, status) => {
            if (status === 'OK') resolve(result);
            else reject(new Error(status));
          }
        );
      });

    (async () => {
      setRouteLoading(true);
      try {
        const points = dropPath;
        const all = [];
        let i = 0;
        while (i < points.length - 1) {
          const remaining = points.length - 1 - i;
          const take = Math.min(remaining, MAX_WPS + 1);
          const origin = points[i];
          const destination = points[i + take];
          const waypoints = points.slice(i + 1, i + take);
          const res = await fetchSegment(origin, destination, waypoints);
          const seg = res.routes[0].overview_path.map((ll) => ({
            lat: ll.lat(),
            lng: ll.lng()
          }));
          // Avoid duplicating the join point between adjacent chunks.
          if (all.length > 0 && seg.length > 0) seg.shift();
          all.push(...seg);
          i += take;
        }
        if (!cancelled) setRoutePath(all);
      } catch {
        // Fall back to the straight-line skeleton on failure (quota, no route, etc.).
        if (!cancelled) setRoutePath([]);
      } finally {
        if (!cancelled) setRouteLoading(false);
      }
    })();

    return () => {
      cancelled = true;
    };
  }, [isLoaded, dropPath]);

  // Numbered step icon as a data URL — drawn fresh per render so we can pass
  // the step number into the SVG without juggling external assets. Color is
  // brand purple to match the planned-route polyline below.
  const stepIcon = (n, isFocused) => {
    const size = isFocused ? 38 : 32;
    const color = isFocused ? '#4D1C61' : '#662582';
    const svg = encodeURIComponent(
      `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="${size}" height="${size}">` +
        `<circle cx="16" cy="16" r="14" fill="${color}" stroke="white" stroke-width="3"/>` +
        `<text x="16" y="21" text-anchor="middle" font-family="Arial,sans-serif" font-size="14" font-weight="700" fill="white">${n}</text>` +
        `</svg>`
    );
    return `data:image/svg+xml;charset=UTF-8,${svg}`;
  };

  const headerBar = (
    <Stack
      direction="row"
      alignItems="center"
      spacing={1.5}
      sx={{
        px: 2,
        py: 1.25,
        borderBottom: '1px solid rgba(15, 23, 42, 0.08)',
        background: 'linear-gradient(135deg, #662582 0%, #9255AB 100%)',
        color: '#fff',
        flexShrink: 0
      }}
    >
      <MdRoute size={20} />
      <Stack sx={{ flex: 1, minWidth: 0 }}>
        <Typography sx={{ fontWeight: 700, fontSize: 15, lineHeight: 1.2 }}>
          Planned route{riderName ? ` — ${riderName}` : ''}
        </Typography>
        {dateRange && (
          <Typography sx={{ fontSize: 12, opacity: 0.85 }}>{dateRange}</Typography>
        )}
      </Stack>
      {details && details.length > 0 && (
        <Typography sx={{ fontSize: 12, opacity: 0.9, fontWeight: 600 }}>
          {details.length} {details.length === 1 ? 'stop' : 'stops'}
          {routeLoading ? ' · resolving route…' : ''}
        </Typography>
      )}
      {onClose && (
        <IconButton size="small" onClick={onClose} sx={{ color: '#fff' }} aria-label="Close">
          <MdClose />
        </IconButton>
      )}
    </Stack>
  );

  // Loading state — route fetch in flight OR Google Maps script not ready yet.
  if (loading || !isLoaded) {
    return (
      <Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
        {headerBar}
        <Stack alignItems="center" justifyContent="center" sx={{ flex: 1, gap: 1.5 }}>
          <CircularProgress size={32} />
          <Typography sx={{ color: '#64748b', fontSize: 13 }}>
            {loading ? 'Loading planned route…' : 'Loading map…'}
          </Typography>
        </Stack>
      </Box>
    );
  }

  // Empty state — fetched but rider has no deliveries with drop coords in the
  // selected window.
  if (!details || details.length === 0) {
    return (
      <Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
        {headerBar}
        <Stack alignItems="center" justifyContent="center" sx={{ flex: 1, gap: 1, p: 3 }}>
          <Typography sx={{ color: '#1e293b', fontWeight: 700, fontSize: 16 }}>
            No planned route for this rider
          </Typography>
          <Typography sx={{ color: '#64748b', fontSize: 13, textAlign: 'center', maxWidth: 360 }}>
            There are no deliveries with drop coordinates assigned to this rider for the selected date range.
          </Typography>
        </Stack>
      </Box>
    );
  }

  return (
    <Box sx={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
      {headerBar}
      <Box sx={{ flex: 1, minHeight: 0 }}>
        <GoogleMap
          mapContainerStyle={containerStyle}
          onLoad={(map) => (mapRef.current = map)}
          center={dropPath[0]}
          zoom={14}
          options={{
            streetViewControl: false,
            mapTypeControl: false,
            fullscreenControl: false
          }}
        >
          {routePath.length > 0 ? (
            <>
              {/* Translucent backdrop so the route stays legible on busy tiles. */}
              <Polyline
                path={routePath}
                options={{ strokeColor: '#662582', strokeOpacity: 0.25, strokeWeight: 8 }}
              />
              {/* Road-following planned route from the Directions API. */}
              <Polyline
                path={routePath}
                options={{ strokeColor: '#662582', strokeOpacity: 0.95, strokeWeight: 4 }}
              />
            </>
          ) : (
            // Fallback while Directions is in flight (or if it fails) — dashed
            // straight-line skeleton between drop pins in step order.
            <Polyline
              path={dropPath}
              options={{
                strokeColor: '#662582',
                strokeOpacity: 0,
                strokeWeight: 0,
                icons: [
                  {
                    icon: {
                      path: 'M 0,-1 0,1',
                      strokeOpacity: 0.6,
                      strokeColor: '#662582',
                      scale: 3
                    },
                    offset: '0',
                    repeat: '14px'
                  }
                ]
              }}
            />
          )}

          {details.map((d, i) => {
            const stepNum = d.step || i + 1;
            const isFocused = focusedStep === d.deliveryid;
            return (
              <Marker
                key={`step-${d.deliveryid || d.orderid || i}`}
                position={{ lat: d.dropLat, lng: d.dropLng }}
                icon={{ url: stepIcon(stepNum, isFocused) }}
                onClick={() => setFocusedStep(isFocused ? null : d.deliveryid)}
                zIndex={isFocused ? 1000 : stepNum}
              >
                {isFocused && (
                  <InfoWindow onCloseClick={() => setFocusedStep(null)}>
                    <Box sx={{ minWidth: 180, fontFamily: 'inherit' }}>
                      <Typography sx={{ fontWeight: 800, fontSize: 13, color: '#0f172a' }}>
                        Step {stepNum} · {d.customer}
                      </Typography>
                      {d.address && (
                        <Typography sx={{ fontSize: 12, color: '#475569', mt: 0.5 }}>
                          {d.address}
                        </Typography>
                      )}
                      {d.expectedTime && (
                        <Typography sx={{ fontSize: 12, color: '#64748b', mt: 0.5 }}>
                          ETA {String(d.expectedTime).slice(11, 16) || d.expectedTime}
                        </Typography>
                      )}
                      {d.orderid && (
                        <Typography sx={{ fontSize: 11, color: '#94a3b8', mt: 0.5 }}>
                          Order #{d.orderid}
                        </Typography>
                      )}
                    </Box>
                  </InfoWindow>
                )}
              </Marker>
            );
          })}
        </GoogleMap>
      </Box>
    </Box>
  );
}
