/**
 * Route Planner — pick a starting point + multiple party stops → optimize order → show on map.
 * Uses backend nearest-neighbour TSP for ordering, then OSRM for the actual road polyline + accurate ETA.
 */
import React, { useEffect, useMemo, useState } from "react";
import { useNavigate } from "react-router-dom";
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import { Checkbox } from "@/components/ui/checkbox";
import {
    ArrowLeft, Route, Locate, Loader2, Trash2, Navigation, GripVertical,
} from "lucide-react";
import { toast } from "sonner";
import { api } from "@/lib/api";
import { MapView } from "@/components/maps/MapView";
import { getCurrentPosition, osrmRoute, openInGoogleMaps } from "@/components/maps/mapHelpers";

export default function RoutePlanner() {
    const navigate = useNavigate();
    const [parties, setParties] = useState([]);
    const [search, setSearch] = useState("");
    const [selected, setSelected] = useState({});         // { id: true }
    const [start, setStart] = useState(null);
    const [optimized, setOptimized] = useState(null);
    const [routeGeo, setRouteGeo] = useState(null);
    const [planning, setPlanning] = useState(false);

    useEffect(() => {
        api.get("/parties", { params: { limit: 2000 } })
            .then((r) => setParties(r.data.filter((p) => p.latitude && p.longitude)))
            .catch(() => toast.error("Failed to load parties"));
    }, []);

    const filtered = useMemo(() => {
        const q = search.toLowerCase().trim();
        if (!q) return parties;
        return parties.filter((p) => (p.name || "").toLowerCase().includes(q) || (p.phone || "").includes(q));
    }, [parties, search]);

    const selectedParties = useMemo(() => parties.filter((p) => selected[p.id]), [parties, selected]);

    const useMyLocation = async () => {
        try {
            const p = await getCurrentPosition();
            setStart({ latitude: p.latitude, longitude: p.longitude });
            toast.success("Start set to your GPS");
        } catch (e) { toast.error("GPS unavailable"); }
    };

    const plan = async () => {
        if (!start) { toast.error("Set a start point first"); return; }
        if (selectedParties.length < 1) { toast.error("Pick at least one stop"); return; }
        setPlanning(true);
        try {
            const stops = selectedParties.map((p) => ({
                id: p.id, name: p.name, latitude: p.latitude, longitude: p.longitude,
            }));
            const { data } = await api.post("/maps/route", { start, stops });
            setOptimized(data);
            // Fetch real OSRM polyline + accurate duration
            const coords = [[start.latitude, start.longitude], ...data.order.map((s) => [s.latitude, s.longitude]), [start.latitude, start.longitude]];
            const route = await osrmRoute(coords);
            setRouteGeo(route);
            toast.success(`Route optimized · ${data.order.length} stops · ${data.total_km.toFixed(1)} km`);
        } catch (e) { toast.error("Route planning failed"); }
        finally { setPlanning(false); }
    };

    const reset = () => { setSelected({}); setOptimized(null); setRouteGeo(null); };

    const markers = useMemo(() => {
        const out = [];
        if (start) {
            out.push({ id: "start", lat: start.latitude, lng: start.longitude, label: "Start", color: "#ef4444", letter: "S" });
        }
        const list = optimized ? optimized.order : selectedParties;
        list.forEach((s, i) => {
            out.push({
                id: `stop-${s.id}-${i}`,
                lat: s.latitude, lng: s.longitude,
                label: optimized ? `${i + 1}. ${s.name}` : s.name,
                subtitle: optimized ? `Leg ${s.leg_km?.toFixed(2) || "?"} km` : undefined,
                color: "#3b82f6", letter: optimized ? String(i + 1) : "C",
            });
        });
        return out;
    }, [start, selectedParties, optimized]);

    const polyline = routeGeo
        ? routeGeo.geometry.coordinates.map(([lng, lat]) => [lat, lng])
        : (optimized
            ? [[start.latitude, start.longitude], ...optimized.order.map((s) => [s.latitude, s.longitude]), [start.latitude, start.longitude]]
            : null);

    return (
        <div className="space-y-4" data-testid="route-planner-page">
            <div className="flex flex-wrap items-center justify-between gap-3">
                <div className="flex items-center gap-3">
                    <Button size="sm" variant="ghost" onClick={() => navigate("/maps")}><ArrowLeft className="h-4 w-4 mr-1" /> Map Dashboard</Button>
                    <div>
                        <div className="label-cap">GPS Route</div>
                        <h1 className="font-display text-2xl font-bold tracking-tight">Route Planner</h1>
                    </div>
                </div>
                <div className="flex items-center gap-2">
                    <Button size="sm" variant="outline" onClick={useMyLocation} data-testid="set-start-btn">
                        <Locate className="h-4 w-4 mr-1.5" /> Set Start = My GPS
                    </Button>
                    <Button size="sm" onClick={plan} disabled={planning || !start} className="bg-primary hover:bg-primary/90" data-testid="optimize-btn">
                        {planning ? <Loader2 className="h-4 w-4 animate-spin mr-1.5" /> : <Route className="h-4 w-4 mr-1.5" />}
                        Optimize Route
                    </Button>
                    <Button size="sm" variant="ghost" onClick={reset} data-testid="reset-btn"><Trash2 className="h-4 w-4 mr-1.5" /> Reset</Button>
                </div>
            </div>

            <div className="grid grid-cols-1 lg:grid-cols-12 gap-4">
                <Card className="lg:col-span-4"><CardContent className="p-4 space-y-3">
                    <div className="label-cap">Pick Stops ({selectedParties.length} selected · max 25)</div>
                    <Input value={search} onChange={(e) => setSearch(e.target.value)} placeholder="Search…" className="h-8 text-xs" data-testid="party-search" />
                    <div className="max-h-[500px] overflow-y-auto space-y-1">
                        {filtered.length === 0 && <div className="text-xs text-muted-foreground italic py-4 text-center">No mapped parties found</div>}
                        {filtered.map((p) => (
                            <div key={p.id} className={`flex items-center gap-2 rounded border px-2 py-1.5 ${selected[p.id] ? "border-primary/40 bg-primary/5" : "border-border"}`}>
                                <Checkbox
                                    checked={!!selected[p.id]}
                                    onCheckedChange={(v) => {
                                        if (v && Object.keys(selected).length >= 25) { toast.error("Max 25 stops"); return; }
                                        setSelected((s) => { const n = { ...s }; if (v) n[p.id] = true; else delete n[p.id]; return n; });
                                    }}
                                    data-testid={`select-stop-${p.id}`}
                                />
                                <div className="flex-1 min-w-0">
                                    <div className="text-xs font-medium truncate">{p.name}</div>
                                    <div className="text-[10px] text-muted-foreground truncate">{p.phone || p.address || "—"}</div>
                                </div>
                            </div>
                        ))}
                    </div>
                </CardContent></Card>

                <div className="lg:col-span-8 space-y-3">
                    <Card><CardContent className="p-3">
                        <MapView
                            markers={markers}
                            polyline={polyline}
                            height="500px"
                            cluster={false}
                            testid="route-map"
                        />
                    </CardContent></Card>

                    {optimized && (
                        <Card><CardContent className="p-4 space-y-2">
                            <div className="flex items-center justify-between flex-wrap gap-2">
                                <div className="flex items-center gap-3">
                                    <Badge className="bg-primary/15 text-primary"><Route className="h-3 w-3 mr-1" /> {optimized.order.length} stops</Badge>
                                    <Badge variant="outline">{(routeGeo ? routeGeo.distance_m / 1000 : optimized.total_km).toFixed(2)} km total</Badge>
                                    <Badge variant="outline">
                                        ~{Math.round((routeGeo ? routeGeo.duration_s / 60 : optimized.eta_minutes))} min
                                    </Badge>
                                    {routeGeo && <Badge variant="secondary" className="text-[10px]">OSRM road route</Badge>}
                                </div>
                                <Button size="sm" variant="outline" onClick={() => openInGoogleMaps(start.latitude, start.longitude, "Start")} data-testid="open-gmaps">
                                    <Navigation className="h-3.5 w-3.5 mr-1.5" /> Open in Google Maps
                                </Button>
                            </div>
                            <div className="border-t pt-2 space-y-1">
                                {optimized.order.map((s, i) => (
                                    <div key={`leg-${i}-${s.id}`} className="flex items-center gap-2 text-xs">
                                        <GripVertical className="h-3 w-3 text-muted-foreground" />
                                        <span className="font-mono text-[10px] w-5">{i + 1}.</span>
                                        <span className="flex-1 truncate">{s.name}</span>
                                        <Badge variant="outline" className="text-[10px]">{s.leg_km.toFixed(2)} km</Badge>
                                    </div>
                                ))}
                            </div>
                        </CardContent></Card>
                    )}
                </div>
            </div>
        </div>
    );
}
