"use client";

import { useEffect, useRef, useState } from "react";

import "leaflet/dist/leaflet.css";
import L from "leaflet";
import { MapContainer, Marker, Popup, TileLayer, useMap } from "react-leaflet";

import { OrderTicket } from "@/components/order-ticket/order-ticket";
import { StageBadge } from "@/components/order-ticket/stage-badge";
import { type AuthUser, getAuthUser } from "@/lib/auth";
import type { Order } from "@/lib/order/types";
import { useOrdersStore } from "@/stores/orders/orders-store";

// Fix leaflet default icon in Next.js (icons get hashed at build)
delete (L.Icon.Default.prototype as unknown as Record<string, unknown>)._getIconUrl;
L.Icon.Default.mergeOptions({
  iconRetinaUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png",
  iconUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png",
  shadowUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png",
});

function makeColoredIcon(color: string, label?: string) {
  const labelHtml = label
    ? `<div style="
        position:absolute;bottom:-18px;left:50%;transform:translateX(-50%);
        background:rgba(0,0,0,0.72);color:white;font-size:10px;font-weight:bold;
        padding:1px 4px;border-radius:3px;white-space:nowrap;font-family:monospace;
      ">${label}</div>`
    : "";
  return L.divIcon({
    className: "",
    html: `<div style="position:relative;width:28px;height:28px;">
      <div style="
        width:28px;height:28px;border-radius:50% 50% 50% 0;
        background:${color};border:2px solid white;
        transform:rotate(-45deg);box-shadow:0 2px 6px rgba(0,0,0,.3)
      "></div>
      ${labelHtml}
    </div>`,
    iconSize: [28, 44],
    iconAnchor: [14, 28],
    popupAnchor: [0, -30],
  });
}

/** Estimate remaining drive time in minutes. Avg speed 20 mph. */
function etaLabel(order: { requestedAt?: string; address?: { miles?: number }; stage: string }): string | undefined {
  if (order.stage === "out_for_delivery" && order.address?.miles) {
    const mins = Math.max(1, Math.round((order.address.miles / 20) * 60));
    return `${mins}m`;
  }
  if (order.requestedAt) {
    const diff = new Date(order.requestedAt).getTime() - Date.now();
    if (diff > 0) {
      const mins = Math.floor(diff / 60_000);
      return mins > 0 ? `${mins}m` : "Now";
    }
  }
  return undefined;
}

const STAGE_MAP_COLORS: Record<string, string> = {
  confirmed: "#3b82f6",
  held_before_kitchen: "#eab308",
  sent_to_kitchen: "#f97316",
  preparing: "#f59e0b",
  ready: "#22c55e",
  assigned: "#06b6d4",
  out_for_delivery: "#8b5cf6",
  address_not_found: "#ef4444",
  completed: "#6b7280",
};

function parseGeo(ge: string): [number, number] | null {
  const parts = ge.split(",").map((s) => Number.parseFloat(s.trim()));
  if (parts.length === 2 && !Number.isNaN(parts[0]) && !Number.isNaN(parts[1])) {
    return [parts[0], parts[1]];
  }
  return null;
}

// Auto-fit map bounds to markers
function BoundsUpdater({ positions }: { positions: [number, number][] }) {
  const map = useMap();
  useEffect(() => {
    if (positions.length === 0) return;
    const bounds = L.latLngBounds(positions);
    map.fitBounds(bounds, { padding: [48, 48] });
  }, [map, positions]);
  return null;
}

export default function MapDispatchClient() {
  const [user, setUser] = useState<AuthUser | null>(null);
  const [selectedId, setSelectedId] = useState<string | null>(null);

  const orders = useOrdersStore((s) => s.orders);

  useEffect(() => {
    setUser(getAuthUser());
  }, []);

  const selectedOrder = orders.find((o) => o.id === selectedId);

  // Only show delivery orders with geo coords
  const mappableOrders = orders.filter(
    (o) => o.type === "delivery" && o.address?.ge && o.stage !== "completed",
  );

  const positions = mappableOrders
    .map((o) => parseGeo(o.address!.ge!))
    .filter((p): p is [number, number] => p !== null);

  // Centre on Bracknell by default
  const defaultCenter: [number, number] = [51.4154, -0.7539];

  return (
    <div className="relative h-full">
      <MapContainer
        center={defaultCenter}
        zoom={13}
        style={{ height: "100%", width: "100%" }}
        className="z-0"
      >
        <TileLayer
          attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />

        {positions.length > 0 && <BoundsUpdater positions={positions} />}

        {mappableOrders.map((order) => {
          const coords = parseGeo(order.address!.ge!);
          if (!coords) return null;
          const icon = makeColoredIcon(STAGE_MAP_COLORS[order.stage] ?? "#6b7280", etaLabel(order));
          return (
            <Marker
              key={order.id}
              position={coords}
              icon={icon}
              eventHandlers={{ click: () => setSelectedId(order.id) }}
            >
              <Popup>
                <div className="min-w-[180px] p-1 text-sm">
                  <div className="flex items-center gap-2">
                    <span className="font-mono font-bold">{order.id}</span>
                    <StageBadge stage={order.stage} type={order.type} />
                  </div>
                  <p className="mt-1 font-semibold">{order.customer.na}</p>
                  <p className="text-xs text-gray-500">{order.address?.ad}</p>
                  <button
                    type="button"
                    className="mt-2 w-full rounded bg-blue-600 px-2 py-1 text-white text-xs hover:bg-blue-700"
                    onClick={() => setSelectedId(order.id)}
                  >
                    Open Ticket
                  </button>
                </div>
              </Popup>
            </Marker>
          );
        })}
      </MapContainer>

      {/* Floating OrderTicket deck */}
      {selectedOrder && user && (
        <div
          className="absolute top-4 right-4 z-[1000] flex flex-col overflow-hidden rounded-xl border bg-background shadow-2xl"
          style={{ width: 360, maxHeight: "calc(100% - 2rem)" }}
        >
          <OrderTicket
            order={selectedOrder}
            role={user.role}
            onNew={() => setSelectedId(null)}
            onClose={() => setSelectedId(null)}
          />
          <button
            type="button"
            className="absolute top-1 right-1 z-10 flex size-6 items-center justify-center rounded-full bg-muted text-muted-foreground text-xs hover:bg-destructive hover:text-destructive-foreground"
            onClick={() => setSelectedId(null)}
            title="Close"
          >
            ✕
          </button>
        </div>
      )}

      {/* Legend */}
      <div className="absolute bottom-4 left-4 z-[1000] rounded-lg border bg-background/90 px-3 py-2 shadow-lg backdrop-blur-sm">
        <p className="mb-1.5 font-medium text-xs">Stage</p>
        <div className="space-y-1">
          {Object.entries(STAGE_MAP_COLORS).map(([stage, color]) => (
            <div key={stage} className="flex items-center gap-2">
              <div className="size-3 rounded-full border border-white shadow-sm" style={{ background: color }} />
              <span className="text-[11px] capitalize">{stage.replace(/_/g, " ")}</span>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}
