import React, {
  useEffect,
  useRef,
  useState,
  useCallback,
  ReactNode,
  useMemo,
} from "react";
import { useNavigate } from "react-router-dom";
import { Map, View, Overlay, MapBrowserEvent } from "ol";
import TileLayer from "ol/layer/Tile";
import OSM from "ol/source/OSM";
import VectorLayer from "ol/layer/Vector";
import VectorSource, { VectorSourceEvent } from "ol/source/Vector";
import { Draw, Modify, Select } from "ol/interaction";
import { DrawEvent } from "ol/interaction/Draw";
import { SelectEvent } from "ol/interaction/Select";
import {
  Style,
  Fill,
  Stroke,
  Circle as CircleStyle,
  RegularShape,
} from "ol/style";
import { Point, LineString, Geometry, Polygon } from "ol/geom";
import { transform } from "ol/proj";
import { GeoJSON } from "ol/format";
import {
  Bus,
  RouteIcon,
  MapPin,
  Trash2,
  ArrowRightLeft,
  Landmark,
  Pencil,
  Lasso,
  InfoIcon,
  X,
  Loader2,
} from "lucide-react";
import { toast } from "react-toastify";
import { singleClick, doubleClick } from "ol/events/condition";
import { Feature } from "ol";
import Layer from "ol/layer/Layer";
import Source from "ol/source/Source";
import { FeatureLike } from "ol/Feature";

// --- MAP STORE ---
import { languageInstance } from "@shared"; // Убедитесь, что этот импорт правильный
import { makeAutoObservable } from "mobx";

interface ApiRoute {
  id: number;
  route_number: string;
  path: [number, number][];
}

interface ApiStation {
  id: number;
  name: string;
  latitude: number;
  longitude: number;
}

interface ApiSight {
  id: number;
  name: string;
  description: string;
  latitude: number;
  longitude: number;
}

class MapStore {
  constructor() {
    makeAutoObservable(this);
  }

  routes: ApiRoute[] = [];
  stations: ApiStation[] = [];
  sights: ApiSight[] = [];

  getRoutes = async () => {
    const response = await languageInstance("ru").get("/route");
    console.log(response.data);
    const routesIds = response.data.map((route: any) => route.id);
    for (const id of routesIds) {
      const route = await languageInstance("ru").get(`/route/${id}`);
      this.routes.push({
        id: route.data.id,
        route_number: route.data.route_number,
        path: route.data.path,
      });
    }

    this.routes = this.routes.sort((a, b) =>
      a.route_number.localeCompare(b.route_number)
    );
  };

  getStations = async () => {
    const stations = await languageInstance("ru").get("/station");
    this.stations = stations.data.map((station: any) => ({
      id: station.id,
      name: station.name,
      latitude: station.latitude,
      longitude: station.longitude,
    }));
  };

  getSights = async () => {
    const sights = await languageInstance("ru").get("/sight");
    this.sights = sights.data.map((sight: any) => ({
      id: sight.id,
      name: sight.name,
      description: sight.description,
      latitude: sight.latitude,
      longitude: sight.longitude,
    }));
  };

  deleteFeature = async (featureType: string, id: number) => {
    await languageInstance("ru").delete(`/${featureType}/${id}`);
    if (featureType === "route") {
      this.routes = this.routes.filter((route) => route.id !== id);
    } else if (featureType === "station") {
      this.stations = this.stations.filter((station) => station.id !== id);
    } else if (featureType === "sight") {
      this.sights = this.sights.filter((sight) => sight.id !== id);
    }
  };

  createFeature = async (featureType: string, geoJsonFeature: any) => {
    const { geometry, properties } = geoJsonFeature;
    let data;

    if (featureType === "station") {
      data = {
        name: properties.name || "Новая станция",
        latitude: geometry.coordinates[1],
        longitude: geometry.coordinates[0],
      };
    } else if (featureType === "route") {
      data = {
        route_number: properties.name || "Новый маршрут",
        path: geometry.coordinates,
      };
    } else if (featureType === "sight") {
      data = {
        name: properties.name || "Новая достопримечательность",
        description: properties.description || "",
        latitude: geometry.coordinates[1],
        longitude: geometry.coordinates[0],
      };
    } else {
      throw new Error(`Unknown feature type for creation: ${featureType}`);
    }

    const response = await languageInstance("ru").post(`/${featureType}`, data);

    if (featureType === "route") this.routes.push(response.data);
    else if (featureType === "station") this.stations.push(response.data);
    else if (featureType === "sight") this.sights.push(response.data);

    return response.data;
  };

  updateFeature = async (featureType: string, geoJsonFeature: any) => {
    const { geometry, properties, id } = geoJsonFeature;
    const numericId = parseInt(String(id).split("-")[1], 10);
    if (isNaN(numericId)) {
      throw new Error(`Invalid feature ID for update: ${id}`);
    }

    let data;
    if (featureType === "station") {
      data = {
        name: properties.name,
        latitude: geometry.coordinates[1],
        longitude: geometry.coordinates[0],
      };
    } else if (featureType === "route") {
      data = {
        route_number: properties.name,
        path: geometry.coordinates,
      };
    } else if (featureType === "sight") {
      data = {
        name: properties.name,
        description: properties.description,
        latitude: geometry.coordinates[1],
        longitude: geometry.coordinates[0],
      };
    } else {
      throw new Error(`Unknown feature type for update: ${featureType}`);
    }

    const response = await languageInstance("ru").patch(
      `/${featureType}/${numericId}`,
      data
    );

    if (featureType === "route") {
      const index = this.routes.findIndex((f) => f.id === numericId);
      if (index !== -1) this.routes[index] = response.data;
    } else if (featureType === "station") {
      const index = this.stations.findIndex((f) => f.id === numericId);
      if (index !== -1) this.stations[index] = response.data;
    } else if (featureType === "sight") {
      const index = this.sights.findIndex((f) => f.id === numericId);
      if (index !== -1) this.sights[index] = response.data;
    }

    return response.data;
  };
}

const mapStore = new MapStore();

// --- CONFIGURATION ---
export const mapConfig = {
  center: [30.311, 59.94] as [number, number],
  zoom: 13,
};

// --- SVG ICONS ---
const EditIcon = () => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    className="h-4 w-4 mr-1 sm:mr-2"
    fill="none"
    viewBox="0 0 24 24"
    stroke="currentColor"
  >
    <path
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth={2}
      d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"
    />
  </svg>
);
const LineIconSvg = () => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    className="h-4 w-4 mr-1 sm:mr-2"
    fill="none"
    viewBox="0 0 24 24"
    stroke="currentColor"
  >
    <path
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth={2}
      d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2h10a2 2 0 002-2v-1a2 2 0 012-2h1.945M7.732 4.064A2.5 2.5 0 105.23 6.24m13.54 0a2.5 2.5 0 10-2.502-2.176M12 16.05V21m0-17.948V3"
    />
  </svg>
);

// --- TYPE DEFINITIONS ---
interface MapServiceConfig {
  target: HTMLElement;
  center: [number, number];
  zoom: number;
}

interface HistoryState {
  action: string;
  state: string;
}

type FeatureType = "station" | "route" | "sight";

class MapService {
  private map: Map | null;
  private vectorSource: VectorSource<Feature<Geometry>>;
  private vectorLayer: VectorLayer<VectorSource<Feature<Geometry>>>;
  private tooltipElement: HTMLElement;
  private tooltipOverlay: Overlay | null;
  private mode: string | null;
  private currentDrawingType: "Point" | "LineString" | null;
  private currentDrawingFeatureType: FeatureType | null;
  private currentInteraction: Draw | null;
  private modifyInteraction: Modify;
  private selectInteraction: Select;
  private hoveredFeatureId: string | number | null;
  private history: HistoryState[];
  private historyIndex: number;
  private beforeModifyState: string | null;
  private boundHandlePointerMove: (
    event: MapBrowserEvent<PointerEvent>
  ) => void;
  private boundHandlePointerLeave: () => void;
  private boundHandleContextMenu: (event: MouseEvent) => void;
  private boundHandleKeyDown: (event: KeyboardEvent) => void;
  private lassoInteraction: Draw | null = null;
  private selectedIds: Set<string | number> = new Set();
  private onSelectionChange: ((ids: Set<string | number>) => void) | null =
    null;

  // Styles
  private defaultStyle: Style;
  private selectedStyle: Style;
  private drawStyle: Style;
  private busIconStyle: Style;
  private selectedBusIconStyle: Style;
  private drawBusIconStyle: Style;
  private sightIconStyle: Style;
  private selectedSightIconStyle: Style;
  private drawSightIconStyle: Style;
  private universalHoverStylePoint: Style;
  private hoverSightIconStyle: Style;
  private universalHoverStyleLine: Style;

  // Callbacks
  private setLoading: (loading: boolean) => void;
  private setError: (error: string | null) => void;
  private onModeChangeCallback: (mode: string) => void;
  private onFeaturesChange: (features: Feature<Geometry>[]) => void;
  private onFeatureSelect: (feature: Feature<Geometry> | null) => void;

  constructor(
    config: MapServiceConfig,
    setLoading: (loading: boolean) => void,
    setError: (error: string | null) => void,
    onModeChangeCallback: (mode: string) => void,
    onFeaturesChange: (features: Feature<Geometry>[]) => void,
    onFeatureSelect: (feature: Feature<Geometry> | null) => void,
    tooltipElement: HTMLElement,
    onSelectionChange?: (ids: Set<string | number>) => void
  ) {
    this.map = null;
    this.tooltipElement = tooltipElement;
    this.tooltipOverlay = null;
    this.mode = null;
    this.currentDrawingType = null;
    this.currentDrawingFeatureType = null;
    this.currentInteraction = null;
    this.hoveredFeatureId = null;
    this.history = [];
    this.historyIndex = -1;
    this.beforeModifyState = null;

    this.setLoading = setLoading;
    this.setError = setError;
    this.onModeChangeCallback = onModeChangeCallback;
    this.onFeaturesChange = onFeaturesChange;
    this.onFeatureSelect = onFeatureSelect;

    this.defaultStyle = new Style({
      fill: new Fill({ color: "rgba(66, 153, 225, 0.2)" }),
      stroke: new Stroke({ color: "#3182ce", width: 3 }),
    });

    // ИСПРАВЛЕНИЕ: Удалено свойство image из этого стиля.
    // Оно предназначалось для линий, но применялось и к точкам,
    // создавая ненужный центральный круг.
    this.selectedStyle = new Style({
      fill: new Fill({ color: "rgba(221, 107, 32, 0.3)" }),
      stroke: new Stroke({ color: "#dd6b20", width: 4 }),
    });

    this.drawStyle = new Style({
      fill: new Fill({ color: "rgba(74, 222, 128, 0.3)" }),
      stroke: new Stroke({
        color: "rgba(34, 197, 94, 0.7)",
        width: 2,
        lineDash: [5, 5],
      }),
      image: new CircleStyle({
        radius: 5,
        fill: new Fill({ color: "rgba(34, 197, 94, 0.7)" }),
      }),
    });

    this.busIconStyle = new Style({
      image: new CircleStyle({
        radius: 8,
        fill: new Fill({ color: "rgba(0, 60, 255, 0.8)" }),
        stroke: new Stroke({ color: "#ffffff", width: 1.5 }),
      }),
    });
    this.selectedBusIconStyle = new Style({
      image: new CircleStyle({
        radius: 10,
        fill: new Fill({ color: "rgba(221, 107, 32, 0.9)" }),
        stroke: new Stroke({ color: "#ffffff", width: 2 }),
      }),
    });
    this.drawBusIconStyle = new Style({
      image: new CircleStyle({
        radius: 8,
        fill: new Fill({ color: "rgba(100, 180, 100, 0.8)" }),
        stroke: new Stroke({ color: "#ffffff", width: 1.5 }),
      }),
    });

    this.sightIconStyle = new Style({
      image: new RegularShape({
        fill: new Fill({ color: "rgba(139, 92, 246, 0.8)" }),
        stroke: new Stroke({ color: "#ffffff", width: 2 }),
        points: 5,
        radius: 12,
        radius2: 6,
        angle: 0,
      }),
    });
    this.selectedSightIconStyle = new Style({
      image: new RegularShape({
        fill: new Fill({ color: "rgba(221, 107, 32, 0.9)" }),
        stroke: new Stroke({ color: "#ffffff", width: 2 }),
        points: 5,
        radius: 12,
        radius2: 6,
        angle: 0,
      }),
    });
    this.drawSightIconStyle = new Style({
      image: new RegularShape({
        fill: new Fill({ color: "rgba(100, 180, 100, 0.8)" }),
        stroke: new Stroke({ color: "#ffffff", width: 1.5 }),
        points: 5,
        radius: 12,
        radius2: 6,
        angle: 0,
      }),
    });

    this.universalHoverStylePoint = new Style({
      image: new CircleStyle({
        radius: 11,
        fill: new Fill({ color: "rgba(255, 165, 0, 0.7)" }),
        stroke: new Stroke({ color: "rgba(255,255,255,0.8)", width: 2 }),
      }),
      zIndex: Infinity,
    });
    this.hoverSightIconStyle = new Style({
      image: new RegularShape({
        fill: new Fill({ color: "rgba(255, 165, 0, 0.7)" }),
        stroke: new Stroke({ color: "rgba(255,255,255,0.8)", width: 2 }),
        points: 5,
        radius: 15,
        radius2: 7.5,
        angle: 0,
      }),
      zIndex: Infinity,
    });
    this.universalHoverStyleLine = new Style({
      stroke: new Stroke({ color: "rgba(255, 165, 0, 0.8)", width: 5 }),
      zIndex: Infinity,
    });

    this.vectorSource = new VectorSource<Feature<Geometry>>();
    this.vectorLayer = new VectorLayer({
      source: this.vectorSource,
      style: (featureLike: FeatureLike) => {
        const feature = featureLike as Feature<Geometry>;
        if (!feature) return this.defaultStyle;

        const geometryType = feature.getGeometry()?.getType();
        const fId = feature.getId();
        const featureType = feature.get("featureType");

        const isEditSelected = this.selectInteraction
          ?.getFeatures()
          .getArray()
          .includes(feature);
        const isHovered = this.hoveredFeatureId === fId;
        const isLassoSelected = fId !== undefined && this.selectedIds.has(fId);

        if (geometryType === "Point") {
          const defaultPointStyle =
            featureType === "sight" ? this.sightIconStyle : this.busIconStyle;
          const selectedPointStyle =
            featureType === "sight"
              ? this.selectedSightIconStyle
              : this.selectedBusIconStyle;

          if (isEditSelected) {
            return selectedPointStyle;
          }
          if (isHovered) {
            // Only apply hover styles if not in edit mode
            if (this.mode !== "edit") {
              return featureType === "sight"
                ? this.hoverSightIconStyle
                : this.universalHoverStylePoint;
            }
            return defaultPointStyle;
          }

          if (isLassoSelected) {
            let imageStyle;
            if (featureType === "sight") {
              imageStyle = new RegularShape({
                fill: new Fill({ color: "#14b8a6" }),
                stroke: new Stroke({ color: "#fff", width: 2 }),
                points: 5,
                radius: 12,
                radius2: 6,
                angle: 0,
              });
            } else {
              imageStyle = new CircleStyle({
                radius: 10,
                fill: new Fill({ color: "#14b8a6" }),
                stroke: new Stroke({ color: "#fff", width: 2 }),
              });
            }
            return new Style({ image: imageStyle, zIndex: Infinity });
          }

          return defaultPointStyle;
        } else if (geometryType === "LineString") {
          if (isEditSelected) {
            return this.selectedStyle;
          }
          if (isHovered) {
            return this.universalHoverStyleLine;
          }
          if (isLassoSelected) {
            return new Style({
              stroke: new Stroke({ color: "#14b8a6", width: 6 }),
              zIndex: Infinity,
            });
          }
          return this.defaultStyle;
        }

        return this.defaultStyle;
      },
    });

    this.boundHandlePointerMove = this.handlePointerMove.bind(this);
    this.boundHandlePointerLeave = this.handlePointerLeave.bind(this);
    this.boundHandleContextMenu = this.handleContextMenu.bind(this);
    this.boundHandleKeyDown = this.handleKeyDown.bind(this);

    this.vectorSource.on(
      "addfeature",
      this.handleFeatureEvent.bind(this) as any
    );
    this.vectorSource.on("removefeature", () => this.updateFeaturesInReact());
    this.vectorSource.on(
      "changefeature",
      this.handleFeatureChange.bind(this) as any
    );

    let renderCompleteHandled = false;
    const MAP_LOAD_TIMEOUT = 15000;
    try {
      this.map = new Map({
        target: config.target,
        layers: [new TileLayer({ source: new OSM() }), this.vectorLayer],
        view: new View({
          center: transform(config.center, "EPSG:4326", "EPSG:3857"),
          zoom: config.zoom,
        }),
        controls: [],
      });
      if (this.tooltipElement && this.map) {
        this.tooltipOverlay = new Overlay({
          element: this.tooltipElement,
          offset: [15, 0],
          positioning: "center-left",
        });
        this.map.addOverlay(this.tooltipOverlay);
      }
      this.map.once("rendercomplete", () => {
        if (!renderCompleteHandled) {
          this.setLoading(false);
          renderCompleteHandled = true;
          setError(null);
        }
      });
      setTimeout(() => {
        if (!renderCompleteHandled && this.map) {
          this.setLoading(false);
          this.setError("Карта не загрузилась вовремя.");
          renderCompleteHandled = true;
        }
      }, MAP_LOAD_TIMEOUT);
    } catch (error) {
      this.setError("Критическая ошибка при инициализации карты.");
      this.setLoading(false);
      renderCompleteHandled = true;
    }

    this.modifyInteraction = new Modify({
      source: this.vectorSource,
      style: new Style({
        image: new CircleStyle({
          radius: 6,
          fill: new Fill({
            color: "rgba(255, 255, 255, 0.8)",
          }),
          stroke: new Stroke({
            color: "#0099ff",
            width: 2.5,
          }),
        }),
      }),
      deleteCondition: (e: MapBrowserEvent<any>) => doubleClick(e),
    });

    this.selectInteraction = new Select({
      style: (featureLike: FeatureLike) => {
        if (!featureLike || !featureLike.getGeometry) return this.defaultStyle;
        const feature = featureLike as Feature<Geometry>;
        const featureType = feature.get("featureType");
        const geometryType = feature.getGeometry()?.getType();

        if (geometryType === "Point") {
          return featureType === "sight"
            ? this.selectedSightIconStyle
            : this.selectedBusIconStyle;
        }
        return this.selectedStyle;
      },
      condition: singleClick,
      filter: (_: FeatureLike, l: Layer<Source, any> | null) =>
        l === this.vectorLayer,
    });

    this.modifyInteraction.on("modifystart", (event) => {
      const geoJSONFormat = new GeoJSON();
      if (!this.map) return;
      this.beforeModifyState = geoJSONFormat.writeFeatures(
        this.vectorSource.getFeatures(), // Сохраняем все фичи для отката
        {
          dataProjection: "EPSG:4326",
          featureProjection: this.map.getView().getProjection().getCode(),
        }
      );
    });

    this.modifyInteraction.on("modifyend", (event) => {
      if (this.beforeModifyState) {
        this.addStateToHistory("modify", this.beforeModifyState);
        this.beforeModifyState = null;
      }
      this.updateFeaturesInReact();

      event.features.getArray().forEach((feature) => {
        this.saveModifiedFeature(feature as Feature<Geometry>);
      });
    });

    this.lassoInteraction = new Draw({
      type: "Polygon",
      style: new Style({
        stroke: new Stroke({ color: "#14b8a6", width: 2 }),
        fill: new Fill({ color: "rgba(20, 184, 166, 0.1)" }),
      }),
    });
    this.lassoInteraction.setActive(false);
    this.lassoInteraction.on("drawend", (event: DrawEvent) => {
      const geometry = event.feature.getGeometry() as Polygon;
      const extent = geometry.getExtent();
      const selected = new Set<string | number>();

      this.vectorSource.forEachFeatureInExtent(extent, (f) => {
        const geom = f.getGeometry();
        if (geom && geom.getType() === "Point") {
          const pointCoords = (geom as Point).getCoordinates();
          if (geometry.intersectsCoordinate(pointCoords)) {
            if (f.getId() !== undefined) selected.add(f.getId()!);
          }
        } else if (geom && geom.intersectsExtent(extent)) {
          if (f.getId() !== undefined) selected.add(f.getId()!);
        }
      });

      this.setSelectedIds(selected);
      this.deactivateLasso();
    });

    if (this.map) {
      this.map.addInteraction(this.modifyInteraction);
      this.map.addInteraction(this.selectInteraction);
      this.map.addInteraction(this.lassoInteraction);
      this.modifyInteraction.setActive(false);
      this.selectInteraction.setActive(false);
      this.lassoInteraction.setActive(false);

      this.selectInteraction.on("select", (e: SelectEvent) => {
        if (this.mode === "edit") {
          const selFs = e.selected as Feature<Geometry>[];
          this.modifyInteraction.setActive(selFs.length > 0);
          if (selFs.length > 0) {
            this.onFeatureSelect(selFs[0]);
          } else {
            this.onFeatureSelect(null);
          }
        }
      });

      this.map.on("pointermove", this.boundHandlePointerMove as any);
      const targetEl = this.map.getTargetElement();
      if (targetEl instanceof HTMLElement) {
        targetEl.addEventListener("contextmenu", this.boundHandleContextMenu);
        targetEl.addEventListener("pointerleave", this.boundHandlePointerLeave);
      }
      document.addEventListener("keydown", this.boundHandleKeyDown);
      this.activateEditMode();
    }

    if (onSelectionChange) {
      this.onSelectionChange = onSelectionChange;
    }
  }

  public unselect(): void {
    this.selectInteraction.getFeatures().clear();
    this.modifyInteraction.setActive(false);
    this.onFeatureSelect(null);
    this.setSelectedIds(new Set());
  }

  public loadFeaturesFromApi(
    apiStations: typeof mapStore.stations,
    apiRoutes: typeof mapStore.routes,
    apiSights: typeof mapStore.sights
  ): void {
    if (!this.map) return;

    const projection = this.map.getView().getProjection();
    const featuresToAdd: Feature<Geometry>[] = [];

    apiStations.forEach((station) => {
      if (station.longitude == null || station.latitude == null) return;
      const point = new Point(
        transform(
          [station.longitude, station.latitude],
          "EPSG:4326",
          projection
        )
      );
      const feature = new Feature({ geometry: point, name: station.name });
      feature.setId(`station-${station.id}`);
      feature.set("featureType", "station");
      featuresToAdd.push(feature);
    });

    apiRoutes.forEach((route) => {
      if (!route.path || route.path.length === 0) return;
      const coordinates = route.path
        .filter((c) => c[0] != null && c[1] != null)
        .map((c) => transform(c, "EPSG:4326", projection));
      if (coordinates.length === 0) return;
      const line = new LineString(coordinates);
      const feature = new Feature({ geometry: line, name: route.route_number });
      feature.setId(`route-${route.id}`);
      feature.set("featureType", "route");
      featuresToAdd.push(feature);
    });

    apiSights.forEach((sight) => {
      if (sight.longitude == null || sight.latitude == null) return;
      const point = new Point(
        transform([sight.longitude, sight.latitude], "EPSG:4326", projection)
      );
      const feature = new Feature({
        geometry: point,
        name: sight.name,
        description: sight.description,
      });
      feature.setId(`sight-${sight.id}`);
      feature.set("featureType", "sight");
      featuresToAdd.push(feature);
    });

    this.vectorSource.addFeatures(featuresToAdd);
    this.updateFeaturesInReact();
  }

  private addStateToHistory(
    actionDescription: string,
    stateToSave: string
  ): void {
    this.history = this.history.slice(0, this.historyIndex + 1);
    this.history.push({ action: actionDescription, state: stateToSave });
    this.historyIndex = this.history.length - 1;
  }

  private getCurrentStateAsGeoJSON(): string | null {
    if (!this.map) return null;
    const geoJSONFormat = new GeoJSON();
    return geoJSONFormat.writeFeatures(this.vectorSource.getFeatures(), {
      dataProjection: "EPSG:4326",
      featureProjection: this.map.getView().getProjection().getCode(),
    });
  }

  public undo(): void {
    if (this.historyIndex >= 0) {
      const stateToRestore = this.history[this.historyIndex].state;
      this.applyHistoryState(stateToRestore);
      this.historyIndex--;
    } else {
      toast.info("Больше отменять нечего");
    }
  }

  public redo(): void {
    if (this.historyIndex < this.history.length - 1) {
      this.historyIndex++;
      this.applyHistoryState(this.history[this.historyIndex].state);
    } else {
      toast.info("Больше повторять нечего");
    }
  }

  private applyHistoryState(geoJSONState: string): void {
    if (!this.map) return;
    const geoJSONFormat = new GeoJSON();
    const features = geoJSONFormat.readFeatures(geoJSONState, {
      dataProjection: "EPSG:4326",
      featureProjection: this.map.getView().getProjection().getCode(),
    }) as Feature<Geometry>[];
    this.unselect();
    this.vectorSource.clear();
    if (features.length > 0) this.vectorSource.addFeatures(features);
    this.updateFeaturesInReact();
  }

  private updateFeaturesInReact(): void {
    if (this.onFeaturesChange) {
      this.onFeaturesChange(this.vectorSource.getFeatures());
    }
  }

  private handlePointerLeave(): void {
    if (this.hoveredFeatureId) {
      this.hoveredFeatureId = null;
      this.vectorLayer.changed();
    }
    if (this.tooltipOverlay) this.tooltipOverlay.setPosition(undefined);
  }

  private handleKeyDown(event: KeyboardEvent): void {
    if ((event.ctrlKey || event.metaKey) && event.key === "z") {
      event.preventDefault();
      this.undo();
      return;
    }
    if ((event.ctrlKey || event.metaKey) && event.key === "y") {
      event.preventDefault();
      this.redo();
      return;
    }
    if (event.key === "Escape") {
      this.unselect();
    }
  }

  private setMode(newMode: string): void {
    if (!this.map) return;
    const oldMode = this.mode;
    this.mode = newMode;
    if (this.onModeChangeCallback) this.onModeChangeCallback(newMode);

    if (this.hoveredFeatureId && oldMode !== newMode) {
      this.hoveredFeatureId = null;
      this.vectorLayer.changed();
      if (this.tooltipOverlay) this.tooltipOverlay.setPosition(undefined);
    }

    if (this.currentInteraction instanceof Draw) {
      this.map.removeInteraction(this.currentInteraction);
      this.currentInteraction = null;
    }

    if (newMode === "edit") {
      this.selectInteraction.setActive(true);
    } else {
      this.unselect();
      this.selectInteraction.setActive(false);
    }
  }

  public activateEditMode(): void {
    this.currentDrawingType = null;
    this.setMode("edit");
  }

  public startDrawing(
    type: "Point" | "LineString",
    featureType: FeatureType
  ): void {
    if (!this.map) return;

    this.currentDrawingType = type;
    this.currentDrawingFeatureType = featureType;

    const drawingMode = `drawing-${featureType}`;
    this.setMode(drawingMode);

    if (this.currentInteraction instanceof Draw) {
      this.map.removeInteraction(this.currentInteraction);
    }

    let styleForDrawing: Style;
    if (featureType === "station") styleForDrawing = this.drawBusIconStyle;
    else if (featureType === "sight") styleForDrawing = this.drawSightIconStyle;
    else styleForDrawing = this.drawStyle;

    this.currentInteraction = new Draw({
      source: this.vectorSource,
      type,
      style: styleForDrawing,
    });

    let stateBeforeDraw: string | null = null;
    this.currentInteraction.on("drawstart", () => {
      stateBeforeDraw = this.getCurrentStateAsGeoJSON();
    });

    this.currentInteraction.on("drawend", async (event: DrawEvent) => {
      if (stateBeforeDraw) {
        this.addStateToHistory("draw-before", stateBeforeDraw);
      }
      const feature = event.feature as Feature<Geometry>;
      const fType = this.currentDrawingFeatureType;
      if (!fType) return;

      feature.set("featureType", fType);

      let baseName = "",
        namePrefix = "";
      if (fType === "station") {
        baseName = "Станция";
        namePrefix = "Станция ";
      } else if (fType === "sight") {
        baseName = "Достопримечательность";
        namePrefix = "Достопримечательность ";
      } else if (fType === "route") {
        baseName = "Маршрут";
        namePrefix = "Маршрут ";
      }

      const existingNamedFeatures = this.vectorSource
        .getFeatures()
        .filter(
          (f) =>
            f !== feature &&
            f.get("featureType") === fType &&
            (f.get("name") as string)?.startsWith(namePrefix)
        );

      let maxNumber = 0;
      existingNamedFeatures.forEach((f) => {
        const name = f.get("name") as string;
        if (name) {
          const num = parseInt(name.substring(namePrefix.length), 10);
          if (!isNaN(num) && num > maxNumber) maxNumber = num;
        }
      });

      feature.set("name", `${baseName} ${maxNumber + 1}`);

      await this.saveNewFeature(feature);
      this.stopDrawing();
    });

    this.map.addInteraction(this.currentInteraction);
  }

  public startDrawingMarker(): void {
    this.startDrawing("Point", "station");
  }
  public startDrawingLine(): void {
    this.startDrawing("LineString", "route");
  }
  public startDrawingSight(): void {
    this.startDrawing("Point", "sight");
  }

  private stopDrawing() {
    if (this.map && this.currentInteraction) {
      try {
        // @ts-ignore
        this.currentInteraction.abortDrawing();
      } catch (e) {
        /* ignore */
      }
      this.map.removeInteraction(this.currentInteraction);
    }
    this.currentInteraction = null;
    this.currentDrawingType = null;
    this.currentDrawingFeatureType = null;
    this.activateEditMode();
  }

  public finishDrawing(): void {
    if (!this.currentInteraction) return;
    try {
      this.currentInteraction.finishDrawing();
    } catch (e) {
      this.stopDrawing();
    }
  }

  private handleContextMenu(event: MouseEvent): void {
    event.preventDefault();
    if (
      this.mode?.startsWith("drawing-") &&
      this.currentInteraction instanceof Draw
    ) {
      this.finishDrawing();
    }
  }

  private handlePointerMove(event: MapBrowserEvent<PointerEvent>): void {
    if (!this.map || event.dragging) {
      if (this.hoveredFeatureId) {
        this.hoveredFeatureId = null;
        this.vectorLayer.changed();
      }
      if (this.tooltipOverlay) this.tooltipOverlay.setPosition(undefined);
      return;
    }

    const hit = this.map.hasFeatureAtPixel(event.pixel, {
      layerFilter: (l) => l === this.vectorLayer,
      hitTolerance: 5,
    });
    this.map.getTargetElement().style.cursor = hit ? "pointer" : "";

    const featureAtPixel: Feature<Geometry> | undefined =
      this.map.forEachFeatureAtPixel(
        event.pixel,
        (f: FeatureLike) => f as Feature<Geometry>,
        { layerFilter: (l) => l === this.vectorLayer, hitTolerance: 5 }
      );
    const newHoveredFeatureId = featureAtPixel ? featureAtPixel.getId() : null;

    if (this.tooltipOverlay && this.tooltipElement) {
      if (this.mode === "edit" && featureAtPixel) {
        const name = featureAtPixel.get("name");
        if (name) {
          this.tooltipElement.innerHTML = name as string;
          this.tooltipOverlay.setPosition(event.coordinate);
        } else {
          this.tooltipOverlay.setPosition(undefined);
        }
      } else {
        this.tooltipOverlay.setPosition(undefined);
      }
    }

    // Only update hoveredFeatureId if not in edit mode
    if (this.mode !== "edit" && this.hoveredFeatureId !== newHoveredFeatureId) {
      this.hoveredFeatureId = newHoveredFeatureId as string | number | null;
      this.vectorLayer.changed();
    }
  }

  public handleMapClick(event: MapBrowserEvent<any>, ctrlKey: boolean): void {
    if (!this.map || this.mode !== "edit") return;

    const featureAtPixel: Feature<Geometry> | undefined =
      this.map.forEachFeatureAtPixel(
        event.pixel,
        (f: FeatureLike) => f as Feature<Geometry>,
        { layerFilter: (l) => l === this.vectorLayer, hitTolerance: 5 }
      );

    if (!featureAtPixel) {
      if (!ctrlKey) this.unselect();
      return;
    }

    const featureId = featureAtPixel.getId();
    if (featureId === undefined) return;

    if (ctrlKey) {
      const newSet = new Set(this.selectedIds);
      if (newSet.has(featureId)) newSet.delete(featureId);
      else newSet.add(featureId);
      this.setSelectedIds(newSet);
    } else {
      this.setSelectedIds(new Set([featureId]));
    }
  }

  public selectFeature(featureId: string | number | undefined): void {
    if (!this.map || featureId === undefined) {
      this.unselect();
      return;
    }

    const feature = this.vectorSource.getFeatureById(featureId);
    if (!feature) {
      this.unselect();
      return;
    }

    if (this.mode === "edit") {
      this.selectInteraction.getFeatures().clear();
      this.selectInteraction.getFeatures().push(feature);
      const selectEvent = new SelectEvent("select", [feature], []);
      this.selectInteraction.dispatchEvent(selectEvent);
    }

    this.setSelectedIds(new Set([featureId]));

    const view = this.map.getView();
    const geometry = feature.getGeometry();
    if (geometry) {
      if (geometry instanceof Point) {
        view.animate({
          center: geometry.getCoordinates(),
          duration: 500,
          zoom: Math.max(view.getZoom() || 14, 14),
        });
      } else {
        view.fit(geometry.getExtent(), {
          duration: 500,
          padding: [50, 50, 50, 50],
          maxZoom: 15,
        });
      }
    }
  }

  public deleteFeature(
    featureId: string | number | undefined,
    recourse: string
  ): void {
    if (featureId === undefined) return;

    const stateBeforeDelete = this.getCurrentStateAsGeoJSON();

    const numericId = parseInt(String(featureId).split("-")[1], 10);
    if (!recourse || isNaN(numericId)) return;

    const feature = this.vectorSource.getFeatureById(featureId);
    if (!feature) return;

    mapStore
      .deleteFeature(recourse, numericId)
      .then(() => {
        toast.success("Объект успешно удален");
        if (stateBeforeDelete)
          this.addStateToHistory("delete", stateBeforeDelete);
        this.vectorSource.removeFeature(feature);
        this.unselect();
      })
      .catch((err) => {
        toast.error("Ошибка при удалении объекта");
        console.error("Delete failed:", err);
      });
  }

  public deleteMultipleFeatures(featureIds: (string | number)[]): void {
    if (!featureIds || featureIds.length === 0) return;

    const stateBeforeDelete = this.getCurrentStateAsGeoJSON();

    const deletePromises = Array.from(featureIds).map((id) => {
      const feature = this.vectorSource.getFeatureById(id);
      if (!feature) return Promise.resolve();

      const recourse = String(id).split("-")[0];
      const numericId = parseInt(String(id).split("-")[1], 10);
      if (recourse && !isNaN(numericId)) {
        return mapStore.deleteFeature(recourse, numericId).then(() => feature); // Возвращаем фичу в случае успеха
      }
      return Promise.resolve();
    });

    Promise.all(deletePromises)
      .then((deletedFeatures) => {
        const successfulDeletes = deletedFeatures.filter((f) => f);
        if (successfulDeletes.length > 0) {
          if (stateBeforeDelete)
            this.addStateToHistory("multiple-delete", stateBeforeDelete);
          successfulDeletes.forEach((f) =>
            this.vectorSource.removeFeature(f as Feature<Geometry>)
          );
          toast.success(`Удалено ${successfulDeletes.length} объект(ов).`);
          this.unselect();
        }
      })
      .catch((err) => {
        toast.error("Произошла ошибка при массовом удалении");
        console.error("Bulk delete failed:", err);
      });
  }

  public getAllFeaturesAsGeoJSON(): string | null {
    if (!this.vectorSource || !this.map) return null;
    const feats = this.vectorSource.getFeatures();
    if (feats.length === 0) return null;
    const geoJSONFmt = new GeoJSON();
    return geoJSONFmt.writeFeatures(feats, {
      dataProjection: "EPSG:4326",
      featureProjection: this.map.getView().getProjection(),
    });
  }

  public destroy(): void {
    if (this.map) {
      document.removeEventListener("keydown", this.boundHandleKeyDown);
      const targetEl = this.map.getTargetElement();
      if (targetEl instanceof HTMLElement) {
        targetEl.removeEventListener(
          "contextmenu",
          this.boundHandleContextMenu
        );
        targetEl.removeEventListener(
          "pointerleave",
          this.boundHandlePointerLeave
        );
      }
      this.map.un("pointermove", this.boundHandlePointerMove as any);
      if (this.tooltipOverlay) this.map.removeOverlay(this.tooltipOverlay);
      this.vectorSource.clear();
      this.map.setTarget(undefined);
      this.map = null;
    }
  }

  private handleFeatureEvent(
    event: VectorSourceEvent<Feature<Geometry>>
  ): void {
    if (!event.feature) return;
    const feature = event.feature;
    if (!feature.getId()) {
      feature.setId(Date.now() + Math.random().toString(36).substr(2, 9));
    }
    this.updateFeaturesInReact();
  }

  private handleFeatureChange(
    event: VectorSourceEvent<Feature<Geometry>>
  ): void {
    if (!event.feature) return;
    this.updateFeaturesInReact();
  }

  public activateLasso() {
    if (this.lassoInteraction && this.map) {
      this.lassoInteraction.setActive(true);
      this.setMode("lasso");
    }
  }

  public deactivateLasso() {
    if (this.lassoInteraction && this.map) {
      this.lassoInteraction.setActive(false);
      this.setMode("edit");
    }
  }

  public setSelectedIds(ids: Set<string | number>) {
    this.selectedIds = new Set(ids);
    if (this.onSelectionChange) this.onSelectionChange(this.selectedIds);
    this.vectorLayer.changed();
  }

  public getSelectedIds() {
    return new Set(this.selectedIds);
  }
  public setOnSelectionChange(cb: (ids: Set<string | number>) => void) {
    this.onSelectionChange = cb;
  }
  public toggleLasso() {
    if (this.mode === "lasso") this.deactivateLasso();
    else this.activateLasso();
  }
  public getMap(): Map | null {
    return this.map;
  }

  private async saveModifiedFeature(feature: Feature<Geometry>) {
    const featureType = feature.get("featureType") as FeatureType;
    const featureId = feature.getId();
    if (!featureType || featureId === undefined || !this.map) return;

    if (typeof featureId === "number" || !String(featureId).includes("-")) {
      console.warn(
        "Skipping save for feature with non-standard ID:",
        featureId
      );
      return;
    }

    const geoJSONFormat = new GeoJSON({
      dataProjection: "EPSG:4326",
      featureProjection: this.map.getView().getProjection(),
    });
    const featureGeoJSON = geoJSONFormat.writeFeatureObject(feature);

    try {
      await mapStore.updateFeature(featureType, featureGeoJSON);
      toast.success(`"${feature.get("name")}" успешно обновлен.`);
    } catch (error) {
      console.error("Failed to update feature:", error);
      toast.error(
        `Не удалось обновить "${feature.get("name")}". Отмена изменений...`
      );
      this.undo();
    }
  }

  private async saveNewFeature(feature: Feature<Geometry>) {
    const featureType = feature.get("featureType") as FeatureType;
    if (!featureType || !this.map) return;

    const geoJSONFormat = new GeoJSON({
      dataProjection: "EPSG:4326",
      featureProjection: this.map.getView().getProjection(),
    });

    const featureGeoJSON = geoJSONFormat.writeFeatureObject(feature);
    const tempId = feature.getId();

    try {
      const createdFeatureData = await mapStore.createFeature(
        featureType,
        featureGeoJSON
      );
      const newName =
        featureType === "route"
          ? createdFeatureData.route_number
          : createdFeatureData.name;
      toast.success(`"${newName}" создано.`);

      const newFeatureId = `${featureType}-${createdFeatureData.id}`;
      feature.setId(newFeatureId);
      feature.set("name", newName);

      this.updateFeaturesInReact();
      this.selectFeature(newFeatureId);
    } catch (error) {
      console.error("Failed to save new feature:", error);
      toast.error("Не удалось сохранить объект.");
      if (tempId) {
        const tempFeature = this.vectorSource.getFeatureById(tempId);
        if (tempFeature) this.vectorSource.removeFeature(tempFeature);
      }
      this.undo(); // Откатываем состояние до момента начала рисования
    }
  }
}

// --- MAP CONTROLS COMPONENT ---
interface MapControlsProps {
  mapService: MapService | null;
  activeMode: string;
  isLassoActive: boolean;
  isUnselectDisabled: boolean;
}

interface ControlItem {
  mode: string;
  title: string;
  longTitle: string;
  icon: React.ReactNode;
  action: () => void;
  isActive?: boolean;
  disabled?: boolean;
}

const MapControls: React.FC<MapControlsProps> = ({
  mapService,
  activeMode,
  isLassoActive,
  isUnselectDisabled,
}) => {
  if (!mapService) return null;

  const controls: ControlItem[] = [
    {
      mode: "edit",
      title: "Редактировать",
      longTitle: "Редактирование",
      icon: <EditIcon />,
      action: () => mapService.activateEditMode(),
    },
    {
      mode: "drawing-station",
      title: "Станция",
      longTitle: "Добавить станцию",
      icon: <Bus size={16} className="mr-1 sm:mr-2" />,
      action: () => mapService.startDrawingMarker(),
    },
    {
      mode: "drawing-sight",
      title: "Достопримечательность",
      longTitle: "Добавить достопримечательность",
      icon: <Landmark size={16} className="mr-1 sm:mr-2" />,
      action: () => mapService.startDrawingSight(),
    },
    {
      mode: "drawing-route",
      title: "Маршрут",
      longTitle: "Добавить маршрут (Правый клик для завершения)",
      icon: <LineIconSvg />,
      action: () => mapService.startDrawingLine(),
    },

    {
      mode: "unselect",
      title: "Сбросить",
      longTitle: "Сбросить выделение (Esc)",
      icon: <X size={16} className="mr-1 sm:mr-2" />,
      action: () => mapService.unselect(),
      disabled: isUnselectDisabled,
    },
  ];
  return (
    <div className="absolute top-4 left-1/2 -translate-x-1/2 z-20 flex flex-nowrap justify-center p-2 bg-white/90 backdrop-blur-sm rounded-lg shadow-xl space-x-1 sm:space-x-2">
      {controls.map((c) => {
        const isActive =
          c.isActive !== undefined ? c.isActive : activeMode === c.mode;
        const isDisabled = c.disabled;
        const buttonClasses = `flex items-center px-3 py-2 rounded-md transition-all duration-200 text-xs sm:text-sm font-medium focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-blue-500 focus:ring-opacity-75 ${
          isDisabled
            ? "bg-gray-200 text-gray-400 cursor-not-allowed"
            : isActive
            ? "bg-blue-600 text-white shadow-md hover:bg-blue-700"
            : "bg-gray-100 text-gray-700 hover:bg-blue-100 hover:text-blue-700"
        }`;
        return (
          <button
            key={c.mode}
            className={buttonClasses}
            onClick={c.action}
            title={c.longTitle}
            disabled={isDisabled}
          >
            {c.icon}
            <span className="hidden sm:inline ml-0 sm:ml-1">{c.title}</span>
          </button>
        );
      })}
    </div>
  );
};

// --- MAP SIGHTBAR COMPONENT ---
interface MapSightbarProps {
  mapService: MapService | null;
  mapFeatures: Feature<Geometry>[];
  selectedFeature: Feature<Geometry> | null;
  selectedIds: Set<string | number>;
  setSelectedIds: (ids: Set<string | number>) => void;
  activeSection: string | null;
  setActiveSection: (section: string | null) => void;
}

const MapSightbar: React.FC<MapSightbarProps> = ({
  mapService,
  mapFeatures,
  selectedFeature,
  selectedIds,
  setSelectedIds,
  activeSection,
  setActiveSection,
}) => {
  const navigate = useNavigate();
  const [searchQuery, setSearchQuery] = useState("");

  const filteredFeatures = useMemo(() => {
    if (!searchQuery.trim()) return mapFeatures;
    return mapFeatures.filter((feature) =>
      ((feature.get("name") as string) || "")
        .toLowerCase()
        .includes(searchQuery.toLowerCase())
    );
  }, [mapFeatures, searchQuery]);

  const handleFeatureClick = useCallback(
    (id) => mapService?.selectFeature(id),
    [mapService]
  );

  const handleDeleteFeature = useCallback(
    (id, recourse) => {
      if (
        mapService &&
        window.confirm("Вы действительно хотите удалить этот объект?")
      ) {
        mapService.deleteFeature(id, recourse);
      }
    },
    [mapService]
  );

  const handleCheckboxChange = useCallback(
    (id) => {
      if (id === undefined) return;
      const newSet = new Set(selectedIds);
      if (newSet.has(id)) newSet.delete(id);
      else newSet.add(id);
      setSelectedIds(newSet);
    },
    [selectedIds, setSelectedIds]
  );

  const handleBulkDelete = useCallback(() => {
    if (!mapService || selectedIds.size === 0) return;
    if (
      window.confirm(
        `Вы уверены, что хотите удалить ${selectedIds.size} объект(ов)?`
      )
    ) {
      mapService.deleteMultipleFeatures(Array.from(selectedIds));
      setSelectedIds(new Set());
    }
  }, [mapService, selectedIds, setSelectedIds]);

  const handleEditFeature = useCallback(
    (featureType, fullId) => {
      if (!featureType || !fullId) return;
      const numericId = String(fullId).split("-")[1];
      if (numericId) navigate(`/${featureType}/${numericId}/edit`);
    },
    [navigate]
  );

  const sortFeatures = (
    features,
    currentSelectedIds,
    currentSelectedFeature
  ) => {
    const selectedId = currentSelectedFeature?.getId();
    return [...features].sort((a, b) => {
      const aId = a.getId(),
        bId = b.getId();
      if (selectedId && aId === selectedId) return -1;
      if (selectedId && bId === selectedId) return 1;
      const aSelected = aId !== undefined && currentSelectedIds.has(aId);
      const bSelected = bId !== undefined && currentSelectedIds.has(bId);
      if (aSelected && !bSelected) return -1;
      if (!aSelected && bSelected) return 1;
      return ((a.get("name") as string) || "").localeCompare(
        (b.get("name") as string) || "",
        "ru"
      );
    });
  };

  const toggleSection = (id: string) =>
    setActiveSection(activeSection === id ? null : id);

  const stations = filteredFeatures.filter(
    (f) => f.get("featureType") === "station"
  );
  const lines = filteredFeatures.filter(
    (f) => f.get("featureType") === "route"
  );
  const sights = filteredFeatures.filter(
    (f) => f.get("featureType") === "sight"
  );

  const sortedStations = sortFeatures(stations, selectedIds, selectedFeature);
  const sortedLines = sortFeatures(lines, selectedIds, selectedFeature);
  const sortedSights = sortFeatures(sights, selectedIds, selectedFeature);

  const sections = [
    {
      id: "layers",
      title: `Остановки (${sortedStations.length})`,
      icon: <Bus size={20} />,
      count: sortedStations.length,
      content: (
        <div className="space-y-1 max-h-[500px] overflow-y-auto pr-1">
          {sortedStations.length > 0 ? (
            sortedStations.map((s) => {
              const sId = s.getId(),
                sName = (s.get("name") as string) || "Без названия";
              const isSelected = selectedFeature?.getId() === sId,
                isChecked = sId !== undefined && selectedIds.has(sId);
              return (
                <div
                  key={String(sId)}
                  data-feature-id={sId}
                  className={`flex items-start p-2 rounded-md group transition-colors duration-150 ${
                    isSelected
                      ? "bg-orange-100 border border-orange-300"
                      : "hover:bg-blue-50"
                  }`}
                >
                  <div className="flex-shrink-0 pr-2 pt-1">
                    <input
                      type="checkbox"
                      className="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 cursor-pointer"
                      checked={!!isChecked}
                      onChange={() => handleCheckboxChange(sId)}
                      onClick={(e) => e.stopPropagation()}
                      aria-label={`Выбрать ${sName}`}
                    />
                  </div>
                  <div
                    className="flex flex-col text-gray-800 text-sm flex-grow mr-2 min-w-0 cursor-pointer"
                    onClick={() => handleFeatureClick(sId)}
                  >
                    <div className="flex items-center">
                      <MapPin
                        size={16}
                        className={`mr-1.5 flex-shrink-0 ${
                          isSelected
                            ? "text-orange-500"
                            : "text-blue-500 group-hover:text-blue-600"
                        }`}
                      />
                      <span
                        className={`font-medium truncate ${
                          isSelected
                            ? "text-orange-600"
                            : "group-hover:text-blue-600"
                        }`}
                        title={sName}
                      >
                        {sName}
                      </span>
                    </div>
                  </div>
                  <div className="flex-shrink-0 flex items-center space-x-1 opacity-60 group-hover:opacity-100">
                    <button
                      onClick={(e) => {
                        e.stopPropagation();
                        handleEditFeature(s.get("featureType"), sId);
                      }}
                      className="p-1 rounded-full text-gray-400 hover:text-blue-600 hover:bg-blue-100 transition-colors"
                      title="Редактировать детали"
                    >
                      <Pencil size={16} />
                    </button>
                    <button
                      onClick={(e) => {
                        e.stopPropagation();
                        handleDeleteFeature(sId, "station");
                      }}
                      className="p-1 rounded-full text-gray-400 hover:text-red-600 hover:bg-red-100 transition-colors"
                      title="Удалить"
                    >
                      <Trash2 size={16} />
                    </button>
                  </div>
                </div>
              );
            })
          ) : (
            <p className="text-gray-500 text-sm">Нет остановок.</p>
          )}
        </div>
      ),
    },
    {
      id: "lines",
      title: `Маршруты (${sortedLines.length})`,
      icon: <RouteIcon size={20} />,
      count: sortedLines.length,
      content: (
        <div className="space-y-1 max-h-60 overflow-y-auto pr-1">
          {sortedLines.length > 0 ? (
            sortedLines.map((l) => {
              const lId = l.getId(),
                lName = (l.get("name") as string) || "Без названия";
              const isSelected = selectedFeature?.getId() === lId,
                isChecked = lId !== undefined && selectedIds.has(lId);
              return (
                <div
                  key={String(lId)}
                  data-feature-id={lId}
                  className={`flex items-start p-2 rounded-md group transition-colors duration-150 ${
                    isSelected
                      ? "bg-orange-100 border border-orange-300"
                      : "hover:bg-blue-50"
                  }`}
                >
                  <div className="flex-shrink-0 pr-2 pt-1">
                    <input
                      type="checkbox"
                      className="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 cursor-pointer"
                      checked={!!isChecked}
                      onChange={() => handleCheckboxChange(lId)}
                      onClick={(e) => e.stopPropagation()}
                      aria-label={`Выбрать ${lName}`}
                    />
                  </div>
                  <div
                    className="flex flex-col text-gray-800 text-sm flex-grow mr-2 min-w-0 cursor-pointer"
                    onClick={() => handleFeatureClick(lId)}
                  >
                    <div className="flex items-center">
                      <ArrowRightLeft
                        size={16}
                        className={`mr-1.5 flex-shrink-0 ${
                          isSelected
                            ? "text-orange-500"
                            : "text-purple-500 group-hover:text-purple-600"
                        }`}
                      />
                      <span
                        className={`font-medium truncate ${
                          isSelected
                            ? "text-orange-600"
                            : "group-hover:text-purple-600"
                        }`}
                        title={lName}
                      >
                        {lName}
                      </span>
                    </div>
                  </div>
                  <div className="flex-shrink-0 flex items-center space-x-1 opacity-60 group-hover:opacity-100">
                    <button
                      onClick={(e) => {
                        e.stopPropagation();
                        handleEditFeature(l.get("featureType"), lId);
                      }}
                      className="p-1 rounded-full text-gray-400 hover:text-blue-600 hover:bg-blue-100 transition-colors"
                      title="Редактировать детали"
                    >
                      <Pencil size={16} />
                    </button>
                    <button
                      onClick={(e) => {
                        e.stopPropagation();
                        handleDeleteFeature(lId, "route");
                      }}
                      className="p-1 rounded-full text-gray-400 hover:text-red-600 hover:bg-red-100 transition-colors"
                      title="Удалить"
                    >
                      <Trash2 size={16} />
                    </button>
                  </div>
                </div>
              );
            })
          ) : (
            <p className="text-gray-500 text-sm">Нет маршрутов.</p>
          )}
        </div>
      ),
    },
    {
      id: "sights",
      title: `Достопримечательности (${sortedSights.length})`,
      icon: <Landmark size={20} />,
      count: sortedSights.length,
      content: (
        <div className="space-y-1 max-h-60 overflow-y-auto pr-1">
          {sortedSights.length > 0 ? (
            sortedSights.map((s) => {
              const sId = s.getId(),
                sName = (s.get("name") as string) || "Без названия";
              const isSelected = selectedFeature?.getId() === sId,
                isChecked = sId !== undefined && selectedIds.has(sId);
              return (
                <div
                  key={String(sId)}
                  data-feature-id={sId}
                  className={`flex items-start p-2 rounded-md group transition-colors duration-150 ${
                    isSelected
                      ? "bg-orange-100 border border-orange-300"
                      : "hover:bg-blue-50"
                  }`}
                >
                  <div className="flex-shrink-0 pr-2 pt-1">
                    <input
                      type="checkbox"
                      className="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 cursor-pointer"
                      checked={!!isChecked}
                      onChange={() => handleCheckboxChange(sId)}
                      onClick={(e) => e.stopPropagation()}
                      aria-label={`Выбрать ${sName}`}
                    />
                  </div>
                  <div
                    className="flex items-center text-gray-800 text-sm flex-grow mr-2 min-w-0 cursor-pointer"
                    onClick={() => handleFeatureClick(sId)}
                  >
                    <Landmark
                      size={16}
                      className={`mr-1.5 flex-shrink-0 ${
                        isSelected
                          ? "text-orange-500"
                          : "text-purple-500 group-hover:text-purple-600"
                      }`}
                    />
                    <span
                      className={`font-medium truncate ${
                        isSelected
                          ? "text-orange-600"
                          : "group-hover:text-purple-600"
                      }`}
                      title={sName}
                    >
                      {sName}
                    </span>
                  </div>
                  <div className="flex-shrink-0 flex items-center space-x-1 opacity-60 group-hover:opacity-100">
                    <button
                      onClick={(e) => {
                        e.stopPropagation();
                        handleEditFeature(s.get("featureType"), sId);
                      }}
                      className="p-1 rounded-full text-gray-400 hover:text-blue-600 hover:bg-blue-100 transition-colors"
                      title="Редактировать детали"
                    >
                      <Pencil size={16} />
                    </button>
                    <button
                      onClick={(e) => {
                        e.stopPropagation();
                        handleDeleteFeature(sId, "sight");
                      }}
                      className="p-1 rounded-full text-gray-400 hover:text-red-600 hover:bg-red-100 transition-colors"
                      title="Удалить"
                    >
                      <Trash2 size={16} />
                    </button>
                  </div>
                </div>
              );
            })
          ) : (
            <p className="text-gray-500 text-sm">Нет достопримечательностей.</p>
          )}
        </div>
      ),
    },
  ];

  return (
    <div className="w-[360px] relative bg-gray-50 shadow-lg flex flex-col border-l border-gray-200 h-[90vh]">
      <div className="p-4 bg-gray-700 text-white">
        <h2 className="text-lg font-semibold">Панель управления</h2>
      </div>
      <div className="p-3 border-b border-gray-200 bg-white">
        <input
          type="text"
          placeholder="Поиск по названию..."
          value={searchQuery}
          onChange={(e) => setSearchQuery(e.target.value)}
          className="w-full px-3 py-2 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
        />
      </div>
      <div className="flex-1 flex flex-col min-h-0">
        <div className="flex-1 overflow-y-auto">
          {filteredFeatures.length === 0 && searchQuery ? (
            <div className="p-4 text-center text-gray-500">
              Ничего не найдено.
            </div>
          ) : (
            sections.map(
              (s) =>
                (s.count > 0 || !searchQuery) && (
                  <div
                    key={s.id}
                    className="border-b border-gray-200 last:border-b-0"
                  >
                    <button
                      onClick={() => toggleSection(s.id)}
                      className={`w-full p-3 flex items-center justify-between text-left hover:bg-gray-100 transition-colors duration-150 focus:outline-none focus:bg-gray-100 ${
                        activeSection === s.id
                          ? "bg-gray-100 text-blue-600"
                          : "text-gray-700"
                      }`}
                    >
                      <div className="flex items-center space-x-3">
                        <span
                          className={
                            activeSection === s.id
                              ? "text-blue-600"
                              : "text-gray-600"
                          }
                        >
                          {s.icon}
                        </span>
                        <span className="font-medium text-sm">{s.title}</span>
                      </div>
                      <span
                        className={`transform transition-transform duration-200 text-gray-500 ${
                          activeSection === s.id ? "rotate-180" : ""
                        }`}
                      >
                        ▼
                      </span>
                    </button>
                    <div
                      className={`overflow-hidden transition-all duration-300 ease-in-out ${
                        activeSection === s.id
                          ? "max-h-[600px] opacity-100"
                          : "max-h-0 opacity-0"
                      }`}
                    >
                      <div className="p-3 text-sm text-gray-600 bg-white border-t border-gray-100">
                        {s.content}
                      </div>
                    </div>
                  </div>
                )
            )
          )}
        </div>
      </div>
      <div className="p-3 border-t border-gray-200 bg-gray-50/95 space-y-2">
        {selectedIds.size > 0 && (
          <button
            onClick={handleBulkDelete}
            className="w-full flex items-center justify-center px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 transition-colors"
          >
            <Trash2 size={16} className="mr-2" />
            Удалить выбранное ({selectedIds.size})
          </button>
        )}
      </div>
    </div>
  );
};

// --- MAP PAGE COMPONENT ---
export const MapPage: React.FC = () => {
  const mapRef = useRef<HTMLDivElement | null>(null);
  const tooltipRef = useRef<HTMLDivElement | null>(null);
  const [mapServiceInstance, setMapServiceInstance] =
    useState<MapService | null>(null);
  const [isMapLoading, setIsMapLoading] = useState<boolean>(true);
  const [isDataLoading, setIsDataLoading] = useState<boolean>(true);
  const [error, setError] = useState<string | null>(null);
  const [currentMapMode, setCurrentMapMode] = useState<string>("edit");
  const [mapFeatures, setMapFeatures] = useState<Feature<Geometry>[]>([]);
  const [selectedFeatureForSidebar, setSelectedFeatureForSidebar] =
    useState<Feature<Geometry> | null>(null);
  const [selectedIds, setSelectedIds] = useState<Set<string | number>>(
    new Set()
  );
  const [isLassoActive, setIsLassoActive] = useState<boolean>(false);
  const [showHelp, setShowHelp] = useState<boolean>(false);
  const [activeSectionFromParent, setActiveSectionFromParent] = useState<
    string | null
  >("layers");

  const handleFeaturesChange = useCallback(
    (feats: Feature<Geometry>[]) => setMapFeatures([...feats]),
    []
  );

  const handleFeatureSelectForSidebar = useCallback(
    (feat: Feature<Geometry> | null) => {
      setSelectedFeatureForSidebar(feat);
      if (feat) {
        const featureType = feat.get("featureType");
        const sectionId =
          featureType === "sight"
            ? "sights"
            : featureType === "route"
            ? "lines"
            : "layers";
        setActiveSectionFromParent(sectionId);
        setTimeout(() => {
          document
            .querySelector(`[data-feature-id="${feat.getId()}"]`)
            ?.scrollIntoView({ behavior: "smooth", block: "center" });
        }, 100);
      }
    },
    []
  );

  const handleMapClick = useCallback(
    (event: any) => {
      if (!mapServiceInstance || isLassoActive) return;
      const ctrlKey =
        event.originalEvent.ctrlKey || event.originalEvent.metaKey;
      mapServiceInstance.handleMapClick(event, ctrlKey);
    },
    [mapServiceInstance, isLassoActive]
  );

  useEffect(() => {
    let service: MapService | null = null;
    if (mapRef.current && tooltipRef.current && !mapServiceInstance) {
      setIsMapLoading(true);
      setIsDataLoading(true);
      setError(null);

      const loadInitialData = async (mapService: MapService) => {
        try {
          await Promise.all([
            mapStore.getRoutes(),
            mapStore.getStations(),
            mapStore.getSights(),
          ]);
          mapService.loadFeaturesFromApi(
            mapStore.stations,
            mapStore.routes,
            mapStore.sights
          );
        } catch (e) {
          console.error("Failed to load initial map data:", e);
          setError("Не удалось загрузить данные для карты.");
        } finally {
          setIsDataLoading(false);
        }
      };

      try {
        service = new MapService(
          { ...mapConfig, target: mapRef.current },
          setIsMapLoading,
          setError,
          setCurrentMapMode,
          handleFeaturesChange,
          handleFeatureSelectForSidebar,
          tooltipRef.current,
          setSelectedIds
        );
        setMapServiceInstance(service);
        loadInitialData(service);
      } catch (e: any) {
        setError(
          `Ошибка инициализации карты: ${e.message || "Неизвестная ошибка"}.`
        );
        setIsMapLoading(false);
        setIsDataLoading(false);
      }
    }
    return () => {
      service?.destroy();
      setMapServiceInstance(null);
    };
  }, []);

  useEffect(() => {
    const olMap = mapServiceInstance?.getMap();
    if (olMap) {
      olMap.on("click", handleMapClick);
      return () => {
        olMap.un("click", handleMapClick);
      };
    }
  }, [mapServiceInstance, handleMapClick]);

  useEffect(() => {
    mapServiceInstance?.setOnSelectionChange(setSelectedIds);
  }, [mapServiceInstance]);

  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === "Shift" && mapServiceInstance) {
        mapServiceInstance.activateLasso();
        setIsLassoActive(true);
      }
    };
    const handleKeyUp = (e: KeyboardEvent) => {
      if (e.key === "Shift" && mapServiceInstance) {
        mapServiceInstance.deactivateLasso();
        setIsLassoActive(false);
      }
    };
    window.addEventListener("keydown", handleKeyDown);
    window.addEventListener("keyup", handleKeyUp);
    return () => {
      window.removeEventListener("keydown", handleKeyDown);
      window.removeEventListener("keyup", handleKeyUp);
    };
  }, [mapServiceInstance]);

  useEffect(() => {
    if (mapServiceInstance) {
      mapServiceInstance.toggleLasso = function () {
        if (currentMapMode === "lasso") {
          this.deactivateLasso();
          setIsLassoActive(false);
        } else {
          this.activateLasso();
          setIsLassoActive(true);
        }
      };
    }
  }, [mapServiceInstance, currentMapMode]);

  const showLoader = isMapLoading || isDataLoading;
  const showContent = mapServiceInstance && !showLoader && !error;
  const isAnythingSelected =
    selectedFeatureForSidebar !== null || selectedIds.size > 0;

  return (
    <div className="flex flex-col md:flex-row font-sans bg-gray-100 h-[90vh] overflow-hidden">
      <div className="relative flex-grow flex">
        <div
          ref={mapRef}
          id="map"
          className="flex-1 h-full relative bg-gray-200"
        >
          <div
            ref={tooltipRef}
            className="tooltip ol-tooltip bg-white text-black p-2 rounded shadow-lg text-xs whitespace-nowrap"
            style={{ position: "absolute", pointerEvents: "none" }}
          ></div>
          {showLoader && (
            <div className="absolute inset-0 flex flex-col items-center justify-center bg-gray-500 bg-opacity-50 z-[1001]">
              <Loader2 className="w-12 h-12 text-blue-500 animate-spin mb-3" />
              <div className="text-md font-semibold text-white drop-shadow-md">
                {isMapLoading ? "Загрузка карты..." : "Загрузка данных..."}
              </div>
            </div>
          )}
          {error && !showLoader && (
            <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-red-100 border border-red-400 text-red-700 p-6 rounded-lg shadow-lg z-[1002] text-center max-w-md">
              <h3 className="font-semibold text-lg mb-2">Произошла ошибка</h3>
              <p className="text-sm">{error}</p>
              <button
                onClick={() => window.location.reload()}
                className="mt-4 px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600 transition-colors text-sm"
              >
                Перезагрузить
              </button>
            </div>
          )}
          {isLassoActive && (
            <div className="absolute bottom-4 left-1/2 -translate-x-1/2 bg-blue-600 text-white py-2 px-4 rounded-full shadow-lg text-sm font-medium z-20">
              Режим выделения области.
            </div>
          )}
        </div>
        {showContent && (
          <MapControls
            mapService={mapServiceInstance}
            activeMode={currentMapMode}
            isLassoActive={isLassoActive}
            isUnselectDisabled={!isAnythingSelected}
          />
        )}

        <button
          onClick={() => setShowHelp(!showHelp)}
          className="absolute bottom-4 right-4 z-20 p-2 bg-white rounded-full shadow-md hover:bg-gray-100"
          title="Помощь по клавишам"
        >
          <InfoIcon size={20} />
        </button>

        {showHelp && (
          <div className="absolute bottom-16 right-4 z-20 p-4 bg-white rounded-lg shadow-xl max-w-xs">
            <h4 className="font-bold mb-2">Горячие клавиши:</h4>
            <ul className="text-sm space-y-2">
              <li>
                <span className="font-mono bg-gray-100 px-1 rounded">
                  Shift
                </span>{" "}
                - Режим выделения (лассо)
              </li>
              <li>
                <span className="font-mono bg-gray-100 px-1 rounded">
                  Ctrl + клик
                </span>{" "}
                - Добавить/убрать из выделения
              </li>
              <li>
                <span className="font-mono bg-gray-100 px-1 rounded">Esc</span>{" "}
                - Отменить выделение
              </li>
              <li>
                <span className="font-mono bg-gray-100 px-1 rounded">
                  Ctrl+Z
                </span>{" "}
                - Отменить действие
              </li>
              <li>
                <span className="font-mono bg-gray-100 px-1 rounded">
                  Ctrl+Y
                </span>{" "}
                - Повторить действие
              </li>
            </ul>
            <button
              onClick={() => setShowHelp(false)}
              className="mt-3 text-xs text-blue-600 hover:text-blue-800"
            >
              Закрыть
            </button>
          </div>
        )}
      </div>
      {showContent && (
        <MapSightbar
          mapService={mapServiceInstance}
          mapFeatures={mapFeatures}
          selectedFeature={selectedFeatureForSidebar}
          selectedIds={selectedIds}
          setSelectedIds={setSelectedIds}
          activeSection={activeSectionFromParent}
          setActiveSection={setActiveSectionFromParent}
        />
      )}
    </div>
  );
};
