import { useEffect, useMemo, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
  ActionIcon,
  Badge,
  Box,
  Button,
  Card,
  Container,
  Grid,
  Group,
  Modal,
  Select,
  SimpleGrid,
  Stack,
  Table,
  Text,
  TextInput,
} from "@mantine/core";
import {
  APIProvider,
  InfoWindow,
  Map as GoogleMap,
  Marker,
  useMap,
} from "@vis.gl/react-google-maps";
import { Activity, Pencil, Plus, Radio, Trash2 } from "lucide-react";
import Breadcrumbs from "@/components/ui/Breadcrumbs";
import { useToast } from "@/hooks/use-toast";
import { useAuth } from "@/auth/useAuth";
import { FREIGHT_PERMS, hasPermission } from "@/lib/permissions";
import { vehiclesService } from "@/services/vehicles.service";
import { gpsTrackingService, type GpsDevice } from "@/services/gps-tracking.service";
import { freightBrand } from "@/theme/freight-brand";

// Same default key + env override the portal's LocationPicker uses.
const GOOGLE_MAPS_API_KEY =
  import.meta.env.VITE_GOOGLE_MAPS_API_KEY ||
  "AIzaSyBg4tN31-fgvH_2Ix_TPo6VSfOA2uA5CCI";
const DEFAULT_CENTER = { lat: 9.03, lng: 38.74 }; // Addis Ababa

const toNum = (v: number | string | null | undefined): number | null =>
  v == null || v === "" ? null : Number(v);

const deviceLabel = (d: GpsDevice) =>
  d.vehicle
    ? [d.vehicle.code, d.vehicle.plateNumber].filter(Boolean).join(" · ")
    : d.name || d.imei;

const fmtTime = (iso?: string | null) => {
  if (!iso) return "—";
  const d = new Date(iso);
  return Number.isNaN(d.getTime()) ? "—" : d.toLocaleString();
};

const StatBox = ({ label, value }: { label: string; value: string }) => (
  <Box p="sm" style={{ backgroundColor: "#f8f9fa", borderRadius: 8 }}>
    <Text size="xs" c="dimmed">{label}</Text>
    <Text fw={600} size="sm">{value}</Text>
  </Box>
);

type LatLng = { lat: number; lng: number };

/** Flip a flag once the map (and thus the Maps JS classes) is loaded. */
function ReadyProbe({ onReady }: { onReady: () => void }) {
  const map = useMap();
  useEffect(() => {
    if (map) onReady();
  }, [map, onReady]);
  return null;
}

/** Fit the map to the current markers (or center on a single one). */
function FitBounds({ points }: { points: LatLng[] }) {
  const map = useMap();
  useEffect(() => {
    if (!map || points.length === 0 || typeof google === "undefined") return;
    if (points.length === 1) {
      map.setCenter(points[0]);
      map.setZoom(14);
      return;
    }
    const b = new google.maps.LatLngBounds();
    points.forEach((p) => b.extend(p));
    map.fitBounds(b, 60);
  }, [map, points]);
  return null;
}

/** Lazily reverse-geocode a coordinate to a human address. */
function useAddress(lat: number, lng: number): string | null {
  const [addr, setAddr] = useState<string | null>(null);
  useEffect(() => {
    if (typeof google === "undefined" || !google.maps?.Geocoder) return;
    setAddr(null);
    let cancelled = false;
    new google.maps.Geocoder().geocode({ location: { lat, lng } }, (res, status) => {
      if (cancelled) return;
      setAddr(status === "OK" && res?.[0] ? res[0].formatted_address : "Unknown location");
    });
    return () => { cancelled = true; };
  }, [lat, lng]);
  return addr;
}

/** Hover popup: label, coordinates, speed/course, and the reverse-geocoded place. */
function HoverInfo({
  device,
  lat,
  lng,
  onClose,
}: {
  device: GpsDevice;
  lat: number;
  lng: number;
  onClose: () => void;
}) {
  const address = useAddress(lat, lng);
  return (
    <InfoWindow position={{ lat, lng }} pixelOffset={[0, -46]} onCloseClick={onClose}>
      <div style={{ minWidth: 190, fontSize: 13 }}>
        <div style={{ fontWeight: 600, marginBottom: 2 }}>{deviceLabel(device)}</div>
        <div style={{ fontFamily: "monospace" }}>
          {lat.toFixed(5)}, {lng.toFixed(5)}
        </div>
        <div style={{ color: "#555" }}>
          {toNum(device.lastSpeed) ?? 0} km/h · {device.lastCourse ?? 0}°
        </div>
        <div style={{ color: "#777", marginTop: 4 }}>{address ?? "Locating…"}</div>
      </div>
    </InfoWindow>
  );
}

/** Draw the selected vehicle's recent path as a polyline. */
function RouteTrail({ path }: { path: LatLng[] }) {
  const map = useMap();
  useEffect(() => {
    if (!map || path.length < 2 || typeof google === "undefined") return;
    const line = new google.maps.Polyline({
      path,
      strokeColor: freightBrand.primary,
      strokeOpacity: 0.85,
      strokeWeight: 4,
    });
    line.setMap(map);
    return () => line.setMap(null);
  }, [map, path]);
  return null;
}

export function TrackingPage() {
  const { toast } = useToast();
  const qc = useQueryClient();
  const { user } = useAuth();
  const canManage = hasPermission(user, FREIGHT_PERMS.tracking.manage);
  const [selectedId, setSelectedId] = useState<string | null>(null);
  const [hoverId, setHoverId] = useState<string | null>(null);
  const [mapsReady, setMapsReady] = useState(false);
  const [modalOpen, setModalOpen] = useState(false);
  const [editDevice, setEditDevice] = useState<GpsDevice | null>(null);
  const [form, setForm] = useState({ imei: "", name: "", vehicleId: "" });

  const openRegister = () => {
    setEditDevice(null);
    setForm({ imei: "", name: "", vehicleId: "" });
    setModalOpen(true);
  };
  const openEdit = (d: GpsDevice) => {
    setEditDevice(d);
    setForm({ imei: d.imei, name: d.name ?? "", vehicleId: d.vehicleId ?? "" });
    setModalOpen(true);
  };

  // Poll every 10s so the map tracks live movement.
  const { data: devices = [] } = useQuery({
    queryKey: ["gps", "devices"],
    queryFn: async () => (await gpsTrackingService.listDevices()).data ?? [],
    refetchInterval: 10_000,
  });

  const { data: vehiclesData } = useQuery({
    queryKey: ["vehicles", "all"],
    queryFn: async () => (await vehiclesService.getAll({ limit: 1000 })).data ?? [],
  });
  const vehicleOptions = useMemo(
    () =>
      (vehiclesData ?? []).map((v) => ({
        value: v.id,
        label: `${v.plateNumber} - ${v.manufacturer} ${v.model}`,
      })),
    [vehiclesData],
  );

  const positioned = useMemo(
    () =>
      devices
        .map((d) => ({ d, lat: toNum(d.lastLat), lng: toNum(d.lastLng) }))
        .filter((x): x is { d: GpsDevice; lat: number; lng: number } => x.lat != null && x.lng != null),
    [devices],
  );

  const selected = devices.find((d) => d.id === selectedId) ?? null;
  const onlineCount = devices.filter((d) => d.online).length;

  // Route history for the selected device's vehicle (chronological trail).
  const { data: history = [] } = useQuery({
    queryKey: ["gps", "history", selected?.vehicleId],
    queryFn: async () => (await gpsTrackingService.history(selected!.vehicleId!, 300)).data ?? [],
    enabled: Boolean(selected?.vehicleId),
  });
  const trail = useMemo(
    () => [...history].reverse().map((h) => ({ lat: Number(h.lat), lng: Number(h.lng) })),
    [history],
  );

  // Teardrop pin colored by state with a white truck glyph inside.
  const markerIcon = (d: GpsDevice, selectedFlag: boolean): google.maps.Icon | undefined => {
    // Maps API loads async — Size/Point classes may not exist yet at first render.
    if (typeof google === "undefined" || !google.maps?.Size || !mapsReady) return undefined;
    const color = selectedFlag ? freightBrand.primary : d.online ? "#2f80ed" : "#95a5a6";
    const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="40" height="48" viewBox="0 0 40 48">
      <path d="M20 2C10 2 2 10 2 20c0 12 18 26 18 26s18-14 18-26C38 10 30 2 20 2Z" fill="${color}" stroke="#ffffff" stroke-width="1.5"/>
      <g transform="translate(8,7)" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
        <path d="M14 18V6a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v11a1 1 0 0 0 1 1h1"/>
        <path d="M15 18H9"/>
        <path d="M19 18h2a1 1 0 0 0 1-1v-3.65a1 1 0 0 0-.22-.62l-3.48-4.35A1 1 0 0 0 17.52 8H14"/>
        <circle cx="7" cy="18" r="2"/>
        <circle cx="17" cy="18" r="2"/>
      </g>
    </svg>`;
    return {
      url: `data:image/svg+xml,${encodeURIComponent(svg)}`,
      scaledSize: new google.maps.Size(40, 48),
      anchor: new google.maps.Point(20, 48),
    };
  };

  const saveMutation = useMutation({
    mutationFn: () =>
      editDevice
        ? gpsTrackingService.update(editDevice.id, {
            name: form.name.trim() || undefined,
            vehicleId: form.vehicleId || null,
          })
        : gpsTrackingService.register({
            imei: form.imei.trim(),
            name: form.name.trim() || undefined,
            vehicleId: form.vehicleId || null,
          }),
    onSuccess: () => {
      toast({ title: editDevice ? "Tracker updated" : "Tracker registered" });
      setModalOpen(false);
      setEditDevice(null);
      setForm({ imei: "", name: "", vehicleId: "" });
      void qc.invalidateQueries({ queryKey: ["gps", "devices"] });
    },
    onError: (err: unknown) => {
      const description =
        (err as { response?: { data?: { message?: string } } })?.response?.data?.message ?? "Failed";
      toast({ title: editDevice ? "Update failed" : "Registration failed", description, variant: "destructive" });
    },
  });

  const assignMutation = useMutation({
    mutationFn: ({ id, vehicleId }: { id: string; vehicleId: string | null }) =>
      gpsTrackingService.update(id, { vehicleId }),
    onSuccess: () => {
      toast({ title: "Tracker updated" });
      void qc.invalidateQueries({ queryKey: ["gps", "devices"] });
    },
    onError: () => toast({ title: "Update failed", variant: "destructive" }),
  });

  const deleteMutation = useMutation({
    mutationFn: (id: string) => gpsTrackingService.remove(id),
    onSuccess: () => {
      toast({ title: "Tracker removed" });
      setSelectedId(null);
      void qc.invalidateQueries({ queryKey: ["gps", "devices"] });
    },
    onError: () => toast({ title: "Delete failed", variant: "destructive" }),
  });

  return (
    <Container size="xl" py="xl" px="lg">
      <Breadcrumbs items={[{ label: "Fleet" }, { label: "Vehicle Tracking" }]} />

      <Group justify="space-between" mb="xl">
        <div>
          <Text fw={700} size="xl">Real-Time Vehicle Tracking</Text>
          <Text c="dimmed" size="sm">Live GPS positions from GT06 trackers</Text>
        </div>
        {canManage && (
          <Button leftSection={<Plus size={16} />} color="edr-green" onClick={openRegister}>
            Register tracker
          </Button>
        )}
      </Group>

      <Grid>
        {/* Map */}
        <Grid.Col span={{ base: 12, lg: 8 }}>
          <Card withBorder p="lg">
            <Card.Section p="md" withBorder>
              <Group justify="space-between">
                <Text fw={500}>Live Map</Text>
                <Badge color="edr-green" leftSection={<Radio size={12} />}>
                  {onlineCount} online · {positioned.length} located
                </Badge>
              </Group>
            </Card.Section>
            <Card.Section p="md">
              <Box style={{ height: 500, width: "100%", borderRadius: 8, overflow: "hidden" }}>
                <APIProvider apiKey={GOOGLE_MAPS_API_KEY}>
                  <GoogleMap
                    defaultCenter={DEFAULT_CENTER}
                    defaultZoom={7}
                    gestureHandling="greedy"
                    disableDefaultUI={false}
                    style={{ width: "100%", height: "100%" }}
                  >
                    <ReadyProbe onReady={() => setMapsReady(true)} />
                    {positioned.map(({ d, lat, lng }) => (
                      <Marker
                        key={d.id}
                        position={{ lat, lng }}
                        title={`${deviceLabel(d)}\n${lat.toFixed(5)}, ${lng.toFixed(5)}`}
                        icon={markerIcon(d, d.id === selectedId)}
                        onClick={() => setSelectedId(d.id)}
                        onMouseOver={() => setHoverId(d.id)}
                      />
                    ))}
                    {(() => {
                      const h = positioned.find((p) => p.d.id === hoverId);
                      return h ? (
                        <HoverInfo device={h.d} lat={h.lat} lng={h.lng} onClose={() => setHoverId(null)} />
                      ) : null;
                    })()}
                    <FitBounds points={positioned.map((p) => ({ lat: p.lat, lng: p.lng }))} />
                    {selected?.vehicleId && trail.length > 1 && <RouteTrail path={trail} />}
                  </GoogleMap>
                </APIProvider>
              </Box>
              {positioned.length === 0 && (
                <Text size="sm" c="dimmed" ta="center" mt="sm">
                  No located trackers yet — waiting for GPS fixes.
                </Text>
              )}
            </Card.Section>
          </Card>
        </Grid.Col>

        {/* Sidebar */}
        <Grid.Col span={{ base: 12, lg: 4 }}>
          <Stack gap="md">
            {selected && (
              <Card withBorder p="lg">
                <Stack gap="md">
                  <Group justify="space-between">
                    <Text fw={500}>{deviceLabel(selected)}</Text>
                    <Group gap="xs">
                      <Badge color={selected.online ? "edr-green" : "gray"} leftSection={<Activity size={12} />}>
                        {selected.online ? "Live" : "Offline"}
                      </Badge>
                      {canManage && (
                        <ActionIcon variant="subtle" color="red" aria-label="Remove tracker" onClick={() => deleteMutation.mutate(selected.id)}>
                          <Trash2 size={16} />
                        </ActionIcon>
                      )}
                    </Group>
                  </Group>

                  <SimpleGrid cols={2} spacing="sm">
                    <StatBox label="Latitude" value={toNum(selected.lastLat)?.toFixed(5) ?? "—"} />
                    <StatBox label="Longitude" value={toNum(selected.lastLng)?.toFixed(5) ?? "—"} />
                    <StatBox label="Speed" value={`${toNum(selected.lastSpeed) ?? 0} km/h`} />
                    <StatBox label="Course" value={`${selected.lastCourse ?? 0}°`} />
                    <StatBox label="Voltage" value={selected.voltageLevel != null ? `${selected.voltageLevel}/6` : "—"} />
                    <StatBox label="GSM" value={selected.gsmLevel != null ? `${selected.gsmLevel}/4` : "—"} />
                  </SimpleGrid>

                  <div>
                    <Text size="xs" c="dimmed">IMEI</Text>
                    <Text fw={500} size="sm">{selected.imei}</Text>
                  </div>
                  <div>
                    <Text size="xs" c="dimmed">Last fix</Text>
                    <Text fw={500} size="sm">{fmtTime(selected.lastFixAt)}</Text>
                  </div>
                  {selected.vehicleId && (
                    <Text size="xs" c="dimmed">
                      Showing last {trail.length} fixes as a route trail.
                    </Text>
                  )}

                  <Select
                    label="Assigned vehicle"
                    placeholder="Unassigned"
                    data={vehicleOptions}
                    value={selected.vehicleId ?? null}
                    onChange={(v) => assignMutation.mutate({ id: selected.id, vehicleId: v })}
                    disabled={!canManage}
                    searchable
                    clearable
                  />
                </Stack>
              </Card>
            )}

            <Card withBorder p="lg">
              <Stack gap="md">
                <Text fw={500}>Trackers ({devices.length})</Text>
                <div style={{ maxHeight: 340, overflowY: "auto" }}>
                  <Table>
                    <Table.Tbody>
                      {devices.map((d) => (
                        <Table.Tr
                          key={d.id}
                          style={{ cursor: "pointer", backgroundColor: d.id === selectedId ? freightBrand.mutedBg : "transparent" }}
                          onClick={() => setSelectedId(d.id)}
                        >
                          <Table.Td>
                            <Stack gap={0}>
                              <Text size="sm" fw={600}>{deviceLabel(d)}</Text>
                              <Text size="xs" c="dimmed">{toNum(d.lastSpeed) ?? 0} km/h · {fmtTime(d.lastFixAt)}</Text>
                            </Stack>
                          </Table.Td>
                          <Table.Td align="right">
                            <Group gap={6} justify="flex-end" wrap="nowrap">
                              <Badge color={d.online ? "edr-green" : "gray"} size="sm">{d.online ? "Live" : "Offline"}</Badge>
                              {canManage && (
                                <ActionIcon
                                  variant="subtle"
                                  size="sm"
                                  aria-label="Edit tracker"
                                  onClick={(e) => { e.stopPropagation(); openEdit(d); }}
                                >
                                  <Pencil size={15} />
                                </ActionIcon>
                              )}
                            </Group>
                          </Table.Td>
                        </Table.Tr>
                      ))}
                      {devices.length === 0 && (
                        <Table.Tr>
                          <Table.Td colSpan={2}>
                            <Text size="sm" c="dimmed" ta="center" py="md">No trackers registered yet.</Text>
                          </Table.Td>
                        </Table.Tr>
                      )}
                    </Table.Tbody>
                  </Table>
                </div>
              </Stack>
            </Card>
          </Stack>
        </Grid.Col>
      </Grid>

      {/* Register / edit modal */}
      <Modal
        opened={modalOpen}
        onClose={() => setModalOpen(false)}
        title={editDevice ? "Edit GPS tracker" : "Register GPS tracker"}
        radius="lg"
        centered
      >
        <Stack gap="md">
          <TextInput
            label="IMEI"
            placeholder="15-digit device IMEI"
            required
            disabled={Boolean(editDevice)}
            value={form.imei}
            onChange={(e) => setForm({ ...form, imei: e.currentTarget.value })}
          />
          <TextInput
            label="Name"
            placeholder="Optional label"
            value={form.name}
            onChange={(e) => setForm({ ...form, name: e.currentTarget.value })}
          />
          <Select
            label="Vehicle"
            placeholder="Assign to a vehicle (optional)"
            data={vehicleOptions}
            value={form.vehicleId || null}
            onChange={(v) => setForm({ ...form, vehicleId: v ?? "" })}
            searchable
            clearable
          />
          <Group justify="flex-end">
            <Button variant="default" onClick={() => setModalOpen(false)}>Cancel</Button>
            <Button
              loading={saveMutation.isPending}
              disabled={!form.imei.trim()}
              onClick={() => saveMutation.mutate()}
            >
              {editDevice ? "Save" : "Register"}
            </Button>
          </Group>
        </Stack>
      </Modal>
    </Container>
  );
}

export default TrackingPage;
