import { useEffect, useRef, useState, useCallback } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Slider } from "@/components/ui/slider";
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
import { MapPin, Trash2, Link as LinkIcon } from "lucide-react";
import { L, geocodeAddress, circleDivIcon, addMapboxSatelliteLayer } from "@/lib/leafletMaps";

export interface MapPinData {
  id: string;
  label: string;
  lat: string;
  lng: string;
  status: "available" | "unavailable";
  linked_amenity_id?: string;
}

interface Props {
  pins: MapPinData[];
  onChange: (pins: MapPinData[]) => void;
  zoom?: number;
  onZoomChange?: (zoom: number) => void;
  formAmenities: { id: string; name: string }[];
  lockedView?: { lat: number; lng: number; zoom: number } | null;
  onLockedViewChange?: (v: { lat: number; lng: number; zoom: number } | null) => void;
}

export default function GoogleMapPicker({ pins, onChange, zoom = 16, onZoomChange, formAmenities, lockedView, onLockedViewChange }: Props) {
  const mapRef = useRef<HTMLDivElement>(null);
  const mapInstance = useRef<L.Map | null>(null);
  const markersRef = useRef<L.Marker[]>([]);
  const [searchQuery, setSearchQuery] = useState("");
  const [searching, setSearching] = useState(false);
  const pinsRef = useRef(pins);
  pinsRef.current = pins;

  const syncMarkers = useCallback((currentPins: MapPinData[]) => {
    if (!mapInstance.current) return;
    markersRef.current.forEach(m => m.remove());
    markersRef.current = [];

    const valid = currentPins.filter(p => {
      const lat = parseFloat(p.lat);
      const lng = parseFloat(p.lng);
      return !isNaN(lat) && !isNaN(lng);
    });

    valid.forEach(pin => {
      const lat = parseFloat(pin.lat);
      const lng = parseFloat(pin.lng);
      const marker = L.marker([lat, lng], {
        title: pin.label || "Pin",
        icon: circleDivIcon({
          color: pin.status === "available" ? "#16a34a" : "#dc2626",
          // Smaller pins to match the public amenity view
          size: 18,
          label: pin.label || "",
          fontSize: "9px",
        }),
      }).addTo(mapInstance.current!);
      markersRef.current.push(marker);
    });

    // If a locked view is configured, respect it instead of auto-fitting bounds.
    if (lockedView && typeof lockedView.lat === "number" && typeof lockedView.lng === "number") {
      mapInstance.current.setView([lockedView.lat, lockedView.lng], lockedView.zoom ?? 16);
      return;
    }

    if (valid.length > 0) {
      const bounds = L.latLngBounds(valid.map(p => [parseFloat(p.lat), parseFloat(p.lng)] as [number, number]));
      if (valid.length === 1) {
        mapInstance.current.setView(bounds.getCenter(), 16);
      } else {
        mapInstance.current.fitBounds(bounds, { padding: [40, 40] });
      }
    }
  }, [lockedView]);

  useEffect(() => {
    if (!mapRef.current || mapInstance.current) return;

    const defaultCenter: [number, number] = pins.length > 0 && pins[0].lat
      ? [parseFloat(pins[0].lat), parseFloat(pins[0].lng)]
      : [28.5383, -81.3792];

    const map = L.map(mapRef.current, {
      center: defaultCenter,
      zoom: zoom,
      zoomControl: true,
    });

    void addMapboxSatelliteLayer(map);

    map.on("zoomend", () => onZoomChange?.(map.getZoom()));

    map.on("click", (e: L.LeafletMouseEvent) => {
      const newPin: MapPinData = {
        id: Math.random().toString(36).substr(2, 9),
        label: "",
        lat: e.latlng.lat.toFixed(6),
        lng: e.latlng.lng.toFixed(6),
        status: "available",
      };
      onChange([...pinsRef.current, newPin]);
    });

    mapInstance.current = map;
    syncMarkers(pins);

    return () => {
      map.remove();
      mapInstance.current = null;
      markersRef.current = [];
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    syncMarkers(pins);
  }, [pins, syncMarkers]);

  const handleSearch = async () => {
    if (!searchQuery.trim() || !mapInstance.current) return;
    setSearching(true);
    const result = await geocodeAddress(searchQuery);
    setSearching(false);
    if (result) {
      mapInstance.current.setView([result.lat, result.lng], 17);
    }
  };

  const updatePin = (id: string, updates: Partial<MapPinData>) => {
    onChange(pins.map(p => p.id === id ? { ...p, ...updates } : p));
  };

  const removePin = (id: string) => {
    onChange(pins.filter(p => p.id !== id));
  };

  return (
    <Card>
      <CardHeader className="pb-3">
        <CardTitle className="text-sm flex items-center gap-2">
          <MapPin className="h-4 w-4" /> Map Pins
        </CardTitle>
        <CardDescription className="text-xs">
          Click on the map to drop pins. Configure each pin below.
        </CardDescription>
      </CardHeader>
      <CardContent className="space-y-4">
        <div className="flex gap-2">
          <Input
            placeholder="Search for an address..."
            value={searchQuery}
            onChange={e => setSearchQuery(e.target.value)}
            onKeyDown={e => e.key === "Enter" && (e.preventDefault(), handleSearch())}
            className="text-sm"
          />
          <Button variant="outline" size="sm" onClick={handleSearch} type="button" disabled={searching}>
            {searching ? "..." : "Search"}
          </Button>
        </div>

        <div ref={mapRef} className="w-full h-[350px] rounded-lg border bg-muted z-0" />

        {onLockedViewChange && (
          <div className="flex items-center justify-between gap-2 p-2 rounded-lg border bg-muted/30">
            <div className="text-xs text-muted-foreground">
              {lockedView
                ? <>🔒 Locked view saved · zoom {lockedView.zoom}</>
                : <>Pan/zoom the map to your preferred framing, then save it as the default view.</>}
            </div>
            <div className="flex gap-2 shrink-0">
              <Button
                type="button"
                variant="outline"
                size="sm"
                onClick={() => {
                  if (!mapInstance.current) return;
                  const c = mapInstance.current.getCenter();
                  const z = mapInstance.current.getZoom();
                  onLockedViewChange({ lat: c.lat, lng: c.lng, zoom: z });
                  onZoomChange?.(z);
                }}
              >
                💾 Save view
              </Button>
              {lockedView && (
                <Button
                  type="button"
                  variant="ghost"
                  size="sm"
                  onClick={() => onLockedViewChange(null)}
                >
                  Reset
                </Button>
              )}
            </div>
          </div>
        )}

        <div className="space-y-1">
          <div className="flex items-center justify-between">
            <label className="text-xs font-medium text-muted-foreground">Default Zoom Level</label>
            <span className="text-xs font-mono text-muted-foreground">{zoom}</span>
          </div>
          <Slider
            value={[zoom]}
            onValueChange={([v]) => onZoomChange?.(v)}
            min={1}
            max={19}
            step={1}
          />
        </div>

        {pins.length > 0 && (
          <div className="space-y-2">
            <p className="text-xs font-medium text-muted-foreground">
              {pins.length} pin{pins.length !== 1 ? "s" : ""} placed
            </p>
            {pins.map((pin, idx) => (
              <div key={pin.id} className="flex items-start gap-2 p-3 rounded-lg border bg-background">
                <span className="text-xs text-muted-foreground mt-2 w-5 shrink-0">{idx + 1}</span>
                <div className="flex-1 space-y-2">
                  <Input
                    placeholder="Pin label"
                    value={pin.label}
                    onChange={e => updatePin(pin.id, { label: e.target.value })}
                    className="text-sm"
                  />
                  <div className="flex items-center gap-2 text-xs text-muted-foreground">
                    <span>{pin.lat}, {pin.lng}</span>
                  </div>
                  <div className="flex items-center gap-2 flex-wrap">
                    <Select
                      value={pin.status}
                      onValueChange={v => updatePin(pin.id, { status: v as "available" | "unavailable" })}
                    >
                      <SelectTrigger className="text-sm w-[160px] h-8"><SelectValue /></SelectTrigger>
                      <SelectContent>
                        <SelectItem value="available">✅ Available</SelectItem>
                        <SelectItem value="unavailable">🚫 Unavailable</SelectItem>
                      </SelectContent>
                    </Select>

                    {pin.status === "available" && formAmenities.length > 0 && (
                      <Select
                        value={pin.linked_amenity_id || "none"}
                        onValueChange={v => updatePin(pin.id, { linked_amenity_id: v === "none" ? undefined : v })}
                      >
                        <SelectTrigger className="text-sm flex-1 h-8">
                          <div className="flex items-center gap-1.5">
                            <LinkIcon className="h-3 w-3" />
                            <SelectValue placeholder="Link a form..." />
                          </div>
                        </SelectTrigger>
                        <SelectContent>
                          <SelectItem value="none">No linked form</SelectItem>
                          {formAmenities.map(fa => (
                            <SelectItem key={fa.id} value={fa.id}>{fa.name}</SelectItem>
                          ))}
                        </SelectContent>
                      </Select>
                    )}
                  </div>
                </div>
                <Button
                  variant="ghost"
                  size="icon"
                  className="h-7 w-7 shrink-0 text-muted-foreground hover:text-destructive"
                  onClick={() => removePin(pin.id)}
                  type="button"
                >
                  <Trash2 className="h-3.5 w-3.5" />
                </Button>
              </div>
            ))}
          </div>
        )}
      </CardContent>
    </Card>
  );
}
