import React, { useState, useEffect, useContext, useRef } from "react";
import { MapContainer, TileLayer, Marker, Popup, useMap } from "react-leaflet";
import L from "leaflet";
import "leaflet/dist/leaflet.css";
import axios from "axios";
import { toast } from "react-toastify";

import { AuthContext } from "../context/AuthContext";

// Fix for default marker icons in react-leaflet
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({
  iconRetinaUrl: require("leaflet/dist/images/marker-icon-2x.png"),
  iconUrl: require("leaflet/dist/images/marker-icon.png"),
  shadowUrl: require("leaflet/dist/images/marker-shadow.png"),
});

// Custom marker icons for different street statuses
const createCustomIcon = (color) => {
  return new L.Icon({
    iconUrl: `https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-${color}.png`,
    shadowUrl:
      "https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png",
    iconSize: [25, 41],
    iconAnchor: [12, 41],
    popupAnchor: [1, -34],
    shadowSize: [41, 41],
  });
};

const availableIcon = createCustomIcon("green");
const adoptedIcon = createCustomIcon("blue");
const myStreetIcon = createCustomIcon("red");

// Component to handle map centering on user location
const LocationMarker = ({ userLocation, setUserLocation }) => {
  const map = useMap();

  useEffect(() => {
    if (!userLocation) {
      map
        .locate()
        .on("locationfound", (e) => {
          setUserLocation(e.latlng);
          map.flyTo(e.latlng, 13);
        })
        .on("locationerror", (e) => {
          console.warn("Location access denied:", e.message);
        });
    }
  }, [map, userLocation, setUserLocation]);

  return userLocation === null ? null : (
    <Marker position={userLocation}>
      <Popup>You are here</Popup>
    </Marker>
  );
};

const MapView = () => {
  const { auth } = useContext(AuthContext);
  const [streets, setStreets] = useState([]);
  const [filteredStreets, setFilteredStreets] = useState([]);
  const [totalCount, setTotalCount] = useState(0);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [userLocation, setUserLocation] = useState(null);
  const [selectedStreet, setSelectedStreet] = useState(null);
  const [adoptingStreetId, setAdoptingStreetId] = useState(null);
  const mapRef = useRef();

  // Filter states
  const [searchTerm, setSearchTerm] = useState("");
  const [statusFilter, setStatusFilter] = useState("all");
  const [showMyStreets, setShowMyStreets] = useState(false);
  const [sortBy, setSortBy] = useState("name");
  const [sortOrder, setSortOrder] = useState("asc");

  // Default center (can be changed to your city's coordinates)
  const defaultCenter = [40.7128, -74.006]; // New York City

  useEffect(() => {
    loadStreets();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [searchTerm, statusFilter, showMyStreets, sortBy, sortOrder]);

  const loadStreets = async () => {
    try {
      setLoading(true);
      setError(null);

      // Build query parameters
      const params = new URLSearchParams();
      params.append("limit", "100"); // Load more streets for filtering

      if (searchTerm) {
        params.append("search", searchTerm);
      }

      if (statusFilter !== "all") {
        params.append("status", statusFilter);
      }

      if (showMyStreets && auth.user) {
        params.append("adoptedBy", auth.user._id);
      }

      params.append("sort", sortBy);
      params.append("order", sortOrder);

      const res = await axios.get(`/api/streets?${params.toString()}`);
      
      // Extract data and total count from response
      const streetData = res.data.data || res.data;
      const total = res.headers["x-total-count"] 
        ? parseInt(res.headers["x-total-count"]) 
        : (res.data.totalDocs || streetData.length);

      setStreets(streetData);
      setFilteredStreets(streetData);
      setTotalCount(total);
    } catch (err) {
      console.error("Error loading streets:", err);
      const errorMessage =
        err.response?.data?.msg ||
        err.response?.data?.message ||
        "Failed to load streets. Please try again later.";
      setError(errorMessage);
      toast.error(errorMessage);
    } finally {
      setLoading(false);
    }
  };

  const adoptStreet = async (id) => {
    if (!auth.isAuthenticated) {
      toast.warning("Please login to adopt a street");
      return;
    }

    try {
      setAdoptingStreetId(id);
      const token = localStorage.getItem("token");
      const res = await axios.put(
        `/api/streets/adopt/${id}`,
        {},
        {
          headers: {
            "x-auth-token": token,
          },
        }
      );
      
      // Update both streets and filteredStreets
      const updatedStreet = res.data.street || res.data;
      setStreets(prevStreets =>
        prevStreets.map((street) => (street._id === id ? updatedStreet : street))
      );
      setFilteredStreets(prevFiltered =>
        prevFiltered.map((street) => (street._id === id ? updatedStreet : street))
      );
      setSelectedStreet(null);
      toast.success("Street adopted successfully!");
      
      // Reload to ensure filters are applied correctly
      loadStreets();
    } catch (err) {
      console.error("Error adopting street:", err);
      const errorMessage =
        err.response?.data?.msg ||
        err.response?.data?.message ||
        "Failed to adopt street. Please try again.";
      toast.error(errorMessage);
    } finally {
      setAdoptingStreetId(null);
    }
  };

  const clearFilters = () => {
    setSearchTerm("");
    setStatusFilter("all");
    setShowMyStreets(false);
    setSortBy("name");
    setSortOrder("asc");
  };

  const hasActiveFilters = () => {
    return searchTerm || statusFilter !== "all" || showMyStreets;
  };

  const getMarkerIcon = (street) => {
    if (
      street.adoptedBy &&
      auth.user &&
      street.adoptedBy._id === auth.user._id
    ) {
      return myStreetIcon;
    }
    if (street.status === "available") {
      return availableIcon;
    }
    return adoptedIcon;
  };

  if (loading) {
    return (
      <div className="text-center mt-5">
        <div className="spinner-border" role="status">
          <span className="sr-only">Loading...</span>
        </div>
        <p>Loading map data...</p>
      </div>
    );
  }

  if (error && streets.length === 0) {
    return (
      <div className="alert alert-danger m-3" role="alert">
        <h4 className="alert-heading">Error Loading Map</h4>
        <p>{error}</p>
        <hr />
        <button className="btn btn-primary" onClick={loadStreets}>
          Retry
        </button>
      </div>
    );
  }

  return (
    <div>
      <h1 className="mb-3">Map View</h1>

      {/* Search and Filter Controls */}
      <div className="card mb-3">
        <div className="card-body">
          <div className="row">
            {/* Search Bar */}
            <div className="col-md-4 col-12 mb-2">
              <input
                type="text"
                className="form-control"
                placeholder="Search streets..."
                value={searchTerm}
                onChange={(e) => setSearchTerm(e.target.value)}
                disabled={loading}
              />
            </div>

            {/* Status Filter */}
            <div className="col-md-2 col-6 mb-2">
              <select
                className="form-control"
                value={statusFilter}
                onChange={(e) => setStatusFilter(e.target.value)}
                disabled={loading}
              >
                <option value="all">All Status</option>
                <option value="available">Available</option>
                <option value="adopted">Adopted</option>
              </select>
            </div>

            {/* Sort By */}
            <div className="col-md-2 col-6 mb-2">
              <select
                className="form-control"
                value={sortBy}
                onChange={(e) => setSortBy(e.target.value)}
                disabled={loading}
              >
                <option value="name">Sort by Name</option>
                <option value="adoptedAt">Sort by Date</option>
              </select>
            </div>

            {/* Sort Order */}
            <div className="col-md-2 col-6 mb-2">
              <select
                className="form-control"
                value={sortOrder}
                onChange={(e) => setSortOrder(e.target.value)}
                disabled={loading}
              >
                <option value="asc">Ascending</option>
                <option value="desc">Descending</option>
              </select>
            </div>

            {/* Action Buttons */}
            <div className="col-md-2 col-6 mb-2">
              {hasActiveFilters() && (
                <button
                  className="btn btn-secondary btn-block"
                  onClick={clearFilters}
                  disabled={loading}
                >
                  Clear Filters
                </button>
              )}
            </div>
          </div>

          {/* My Streets Toggle */}
          <div className="row mt-2">
            <div className="col-12">
              {auth.isAuthenticated && (
                <div className="custom-control custom-switch">
                  <input
                    type="checkbox"
                    className="custom-control-input"
                    id="myStreetsToggle"
                    checked={showMyStreets}
                    onChange={(e) => setShowMyStreets(e.target.checked)}
                    disabled={loading}
                  />
                  <label className="custom-control-label" htmlFor="myStreetsToggle">
                    Show only my streets
                  </label>
                </div>
              )}
            </div>
          </div>

          {/* Result Count */}
          <div className="row mt-2">
            <div className="col-12">
              <small className="text-muted">
                {loading ? (
                  "Loading..."
                ) : (
                  <>
                    Showing {filteredStreets.length} of {totalCount} streets
                    {hasActiveFilters() && " (filtered)"}
                  </>
                )}
              </small>
            </div>
          </div>
        </div>
      </div>

      {/* Legend */}
      <div className="mb-3">
        <div className="d-flex align-items-center flex-wrap">
          <span className="mr-3 mb-2">
            <img
              src="https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-green.png"
              alt="Available"
              style={{ height: "20px" }}
            />
            <small className="ml-1">Available</small>
          </span>
          <span className="mr-3 mb-2">
            <img
              src="https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-blue.png"
              alt="Adopted"
              style={{ height: "20px" }}
            />
            <small className="ml-1">Adopted</small>
          </span>
          <span className="mr-3 mb-2">
            <img
              src="https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png"
              alt="My Street"
              style={{ height: "20px" }}
            />
            <small className="ml-1">My Streets</small>
          </span>
        </div>
      </div>

      <div style={{ height: "500px", width: "100%", marginBottom: "20px" }}>
        <MapContainer
          center={defaultCenter}
          zoom={13}
          style={{ height: "100%", width: "100%" }}
          ref={mapRef}
        >
          <TileLayer
            attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
            url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
          />

          <LocationMarker
            userLocation={userLocation}
            setUserLocation={setUserLocation}
          />

          {filteredStreets.map((street) => {
              // Use street coordinates or generate random coordinates for demo
              const position = street.coordinates
                ? [street.coordinates.lat, street.coordinates.lng]
                : [
                    defaultCenter[0] + (Math.random() - 0.5) * 0.1,
                    defaultCenter[1] + (Math.random() - 0.5) * 0.1,
                  ];

              return (
                <Marker
                  key={street._id}
                  position={position}
                  icon={getMarkerIcon(street)}
                  eventHandlers={{
                    click: () => {
                      setSelectedStreet(street);
                    },
                  }}
                >
                  <Popup>
                    <div>
                      <h5>{street.name}</h5>
                      <p>
                        <strong>Status:</strong>{" "}
                        <span
                          className={`badge badge-${
                            street.status === "available"
                              ? "success"
                              : "primary"
                          }`}
                        >
                          {street.status}
                        </span>
                      </p>
                      {street.adoptedBy && (
                        <p>
                          <strong>Adopted by:</strong> {street.adoptedBy.name}
                        </p>
                      )}
                      {street.description && (
                        <p>
                          <strong>Description:</strong> {street.description}
                        </p>
                      )}
                      {street.status === "available" && (
                        <button
                          className="btn btn-sm btn-success"
                          onClick={() => adoptStreet(street._id)}
                          disabled={adoptingStreetId === street._id}
                        >
                          {adoptingStreetId === street._id
                            ? "Adopting..."
                            : "Adopt This Street"}
                        </button>
                      )}
                    </div>
                  </Popup>
                </Marker>
              );
            })}
        </MapContainer>
      </div>

      {selectedStreet && (
        <div className="card">
          <div className="card-body">
            <h5 className="card-title">{selectedStreet.name}</h5>
            <p className="card-text">
              <strong>Status:</strong>{" "}
              <span
                className={`badge badge-${
                  selectedStreet.status === "available" ? "success" : "primary"
                }`}
              >
                {selectedStreet.status}
              </span>
            </p>
            {selectedStreet.adoptedBy && (
              <p className="card-text">
                <strong>Adopted by:</strong> {selectedStreet.adoptedBy.name}
              </p>
            )}
            {selectedStreet.description && (
              <p className="card-text">
                <strong>Description:</strong> {selectedStreet.description}
              </p>
            )}
            {selectedStreet.status === "available" && (
              <button
                className="btn btn-success"
                onClick={() => adoptStreet(selectedStreet._id)}
                disabled={adoptingStreetId === selectedStreet._id}
              >
                {adoptingStreetId === selectedStreet._id
                  ? "Adopting..."
                  : "Adopt This Street"}
              </button>
            )}
            <button
              className="btn btn-secondary ml-2"
              onClick={() => setSelectedStreet(null)}
            >
              Close
            </button>
          </div>
        </div>
      )}

      <div className="mt-3">
        <h3>Street List</h3>
        {loading ? (
          <div className="text-center">
            <div className="spinner-border spinner-border-sm" role="status">
              <span className="sr-only">Loading...</span>
            </div>
            <span className="ml-2">Loading streets...</span>
          </div>
        ) : filteredStreets.length === 0 ? (
          <div className="alert alert-info">
            {hasActiveFilters() 
              ? "No streets match your filters. Try adjusting your search criteria."
              : "No streets available at the moment."}
          </div>
        ) : (
          <ul className="list-group">
            {filteredStreets.map((street) => (
              <li key={street._id} className="list-group-item">
                <div className="d-flex justify-content-between align-items-center">
                  <div>
                    <strong>{street.name}</strong>{" "}
                    <span
                      className={`badge badge-${
                        street.status === "available" ? "success" : "primary"
                      }`}
                    >
                      {street.status}
                    </span>
                    {street.adoptedBy && (
                      <small className="text-muted ml-2">
                        by {street.adoptedBy.name}
                      </small>
                    )}
                  </div>
                  {street.status === "available" && (
                    <button
                      className="btn btn-sm btn-success"
                      onClick={() => adoptStreet(street._id)}
                      disabled={adoptingStreetId === street._id}
                    >
                      {adoptingStreetId === street._id ? "Adopting..." : "Adopt"}
                    </button>
                  )}
                </div>
              </li>
            ))}
          </ul>
        )}
      </div>
    </div>
  );
};

export default MapView;
