import { useCallback, useContext, useEffect, useRef } from "react";
import { useLocation, useNavigate, useParams } from "react-router-dom";
import { AuthContext } from "../context/AuthContext";
import { HouseholdContext } from "../context/HouseholdContext";
import { StoreContext } from "../context/StoreContext";
import LocationMapBottomSheet from "../components/maps/LocationMapBottomSheet";
import LocationMapCanvas from "../components/maps/LocationMapCanvas";
import LocationMapDialogs from "../components/maps/LocationMapDialogs";
import LocationMapSetupPanel from "../components/maps/LocationMapSetupPanel";
import {
  LocationMapLoadErrorState,
  LocationMapMessageState,
} from "../components/maps/LocationMapStateViews";
import LocationMapToolbar from "../components/maps/LocationMapToolbar";
import LocationMapTopbar from "../components/maps/LocationMapTopbar";
import useActionToast from "../hooks/useActionToast";
import useLocationMapDerivedState from "../hooks/useLocationMapDerivedState";
import useLocationMapDraftActions from "../hooks/useLocationMapDraftActions";
import useLocationMapDraftState from "../hooks/useLocationMapDraftState";
import useLocationMapBuying from "../hooks/useLocationMapBuying";
import useLocationMapObjectActions from "../hooks/useLocationMapObjectActions";
import useLocationMapViewControls from "../hooks/useLocationMapViewControls";
import useUnsavedMapLeaveGuard from "../hooks/useUnsavedMapLeaveGuard";
import { getMapStatus } from "../lib/locationMapUtils";
import "../styles/pages/LocationMapManager.css";

function isTextEditingTarget(target) {
  return Boolean(target?.closest?.("input, textarea, select, [contenteditable]"));
}

export default function LocationMapManager() {
  const { storeId, locationId } = useParams();
  const navigate = useNavigate();
  const routeLocation = useLocation();
  const returnPath = routeLocation.state?.returnTo;
  const toast = useActionToast();
  const { username } = useContext(AuthContext);
  const { activeHousehold, loading: householdLoading, hasLoaded } = useContext(HouseholdContext);
  const { stores, activeStore, setActiveStore } = useContext(StoreContext);

  const {
    beginSaving,
    dragState,
    endSaving,
    filters,
    future,
    hasUnsavedChanges,
    history,
    layersOpen,
    loadError,
    loadMap,
    loading,
    mapDraft,
    mapState,
    mode,
    objects,
    previewDraft,
    saving,
    savingAction,
    selectedObjectKey,
    setDragState,
    setFilters,
    setFuture,
    setHasUnsavedChanges,
    setHistory,
    setLayersOpen,
    setMapDraft,
    setMapState,
    setMode,
    setObjects,
    setPreviewDraft,
    setSelectedObjectKey,
    setZoom,
    syncMapDraftFromState,
    zoom,
  } = useLocationMapDraftState({
    activeHousehold,
    hasLoaded,
    householdLoading,
    locationId,
    toast,
  });
  const svgRef = useRef(null);

  const location = mapState?.location || stores.find((store) => String(store.id) === String(locationId));
  const canManage = Boolean(mapState?.can_manage ?? ["owner", "admin"].includes(activeHousehold?.role));
  const {
    hiddenAreaCount,
    mapItems,
    mapSize,
    selectedObject,
    selectedZoneItems,
    unmappedItemCount,
    visibleAssignedItemCount,
    visibleUnmappedItems,
  } = useLocationMapDerivedState({
    filters,
    mapDraft,
    mapState,
    mode,
    objects,
    previewDraft,
    selectedObjectKey,
    username,
  });
  const {
    buyModalItem,
    buyModalItems,
    handleMapBuyCancel,
    handleMapBuyConfirm,
    handleMapBuyNavigate,
    setBuyModalItem,
  } = useLocationMapBuying({
    activeHouseholdId: activeHousehold?.id,
    locationId,
    selectedObject,
    selectedZoneItems,
    setMapState,
    toast,
    visibleUnmappedItems,
  });
  const shouldGuardLeave = canManage && hasUnsavedChanges;

  useEffect(() => {
    const matchingLocation = stores.find((store) => String(store.id) === String(locationId));
    if (matchingLocation && String(activeStore?.id) !== String(matchingLocation.id)) {
      setActiveStore(matchingLocation);
    }
  }, [activeStore?.id, locationId, setActiveStore, stores]);

  const {
    handleCreateBlank,
    handleCreateFromZones,
    handlePublish,
    handleSaveDraft,
  } = useLocationMapDraftActions({
    activeHouseholdId: activeHousehold?.id,
    beginSaving,
    endSaving,
    hasUnsavedChanges,
    locationId,
    mapDraft,
    objects,
    selectedObjectKey,
    setMapState,
    setMode,
    setPreviewDraft,
    syncMapDraftFromState,
    toast,
  });

  const {
    handleAddObject,
    handleDeleteObject,
    handleDuplicateObject,
    handleObjectField,
    handleShowHiddenAreas,
    handleZoneLinkChange,
    expandMapToFitObject,
    pendingDeleteObject,
    remember,
    requestDeleteObject,
    setPendingDeleteObject,
    updateObjects,
  } = useLocationMapObjectActions({
    canManage,
    hiddenAreaCount,
    mapSize,
    mapState,
    objects,
    selectedObject,
    selectedObjectKey,
    setFuture,
    setHasUnsavedChanges,
    setHistory,
    setMapDraft,
    setObjects,
    setSelectedObjectKey,
    toast,
  });

  useEffect(() => {
    setPendingDeleteObject(null);
  }, [activeHousehold?.id, locationId, setPendingDeleteObject]);

  const {
    handleEditMode,
    handleFitMap,
    handlePreviewDraft,
    handleRedo,
    handleUndo,
    handleViewMode,
  } = useLocationMapViewControls({
    filters,
    future,
    hasUnsavedChanges,
    history,
    mapSize,
    mapState,
    mode,
    objects,
    previewDraft,
    saving,
    selectedObjectKey,
    setFuture,
    setHasUnsavedChanges,
    setHistory,
    setLayersOpen,
    setMode,
    setObjects,
    setPreviewDraft,
    setSelectedObjectKey,
    setZoom,
    svgRef,
    syncMapDraftFromState,
    zoom,
  });

  const performBackNavigation = useCallback(() => {
    if (typeof returnPath === "string" && returnPath.startsWith("/")) {
      navigate(returnPath, { replace: true });
      return;
    }
    navigate("/");
  }, [navigate, returnPath]);

  const {
    pendingLeaveTarget,
    requestBackNavigation,
    clearPendingLeave,
    confirmPendingLeave,
  } = useUnsavedMapLeaveGuard({
    shouldGuardLeave,
    navigate,
    performBackNavigation,
  });

  useEffect(() => {
    const hasOpenModal = Boolean(buyModalItem || pendingDeleteObject || pendingLeaveTarget);
    if (!selectedObjectKey || layersOpen || hasOpenModal || typeof window === "undefined") {
      return undefined;
    }

    const handleKeyDown = (event) => {
      if (
        event.defaultPrevented ||
        event.key !== "Escape" ||
        isTextEditingTarget(event.target)
      ) {
        return;
      }

      setSelectedObjectKey(null);
    };

    window.addEventListener("keydown", handleKeyDown);
    return () => window.removeEventListener("keydown", handleKeyDown);
  }, [buyModalItem, layersOpen, pendingDeleteObject, pendingLeaveTarget, selectedObjectKey, setSelectedObjectKey]);

  useEffect(() => {
    const hasOpenModal = Boolean(buyModalItem || pendingDeleteObject || pendingLeaveTarget);
    if (mode !== "edit" || !canManage || hasOpenModal || typeof window === "undefined") {
      return undefined;
    }

    const handleKeyDown = (event) => {
      const wantsSave =
        (event.ctrlKey || event.metaKey) &&
        !event.altKey &&
        event.key.toLowerCase() === "s";

      if (!wantsSave) return;
      event.preventDefault();
      if (saving || !hasUnsavedChanges) return;
      handleSaveDraft();
    };

    window.addEventListener("keydown", handleKeyDown, true);
    return () => window.removeEventListener("keydown", handleKeyDown, true);
  }, [
    buyModalItem,
    canManage,
    handleSaveDraft,
    hasUnsavedChanges,
    mode,
    pendingDeleteObject,
    pendingLeaveTarget,
    saving,
  ]);

  useEffect(() => {
    const hasOpenModal = Boolean(buyModalItem || pendingDeleteObject || pendingLeaveTarget);
    if (
      !selectedObjectKey ||
      mode !== "edit" ||
      !canManage ||
      saving ||
      layersOpen ||
      hasOpenModal ||
      typeof window === "undefined"
    ) {
      return undefined;
    }

    const handleKeyDown = (event) => {
      if (
        event.defaultPrevented ||
        !["Backspace", "Delete"].includes(event.key) ||
        isTextEditingTarget(event.target)
      ) {
        return;
      }

      event.preventDefault();
      requestDeleteObject();
    };

    window.addEventListener("keydown", handleKeyDown, true);
    return () => window.removeEventListener("keydown", handleKeyDown, true);
  }, [
    buyModalItem,
    canManage,
    layersOpen,
    mode,
    pendingDeleteObject,
    pendingLeaveTarget,
    requestDeleteObject,
    saving,
    selectedObjectKey,
  ]);

  if (!hasLoaded || householdLoading || loading) {
    return (
      <LocationMapMessageState
        message="Loading map..."
        location={location}
        status="Loading"
        onBack={requestBackNavigation}
      />
    );
  }

  if (!activeHousehold) {
    return (
      <LocationMapMessageState
        status="Select Household"
      />
    );
  }

  if (loadError) {
    return (
      <LocationMapLoadErrorState
        location={location}
        loadError={loadError}
        onBack={requestBackNavigation}
        onRetry={loadMap}
      />
    );
  }

  const hasAnyMap = Boolean(mapState?.draft_map || mapState?.published_map);
  const hasVisibleOrManageableMap = Boolean(mapState?.published_map || (mapState?.draft_map && canManage));
  const status = getMapStatus(mapState, { mode, previewDraft, hasUnsavedChanges });

  return (
    <div className="location-map-page">
      <LocationMapTopbar location={location} status={status} onBack={requestBackNavigation} />

      <main className="location-map-workspace">
        {hasAnyMap && mode !== "setup" ? (
          <LocationMapToolbar
            mode={mode}
            hasAnyMap={hasAnyMap}
            canManage={canManage}
            saving={saving}
            history={history}
            future={future}
            zoom={zoom}
            setZoom={setZoom}
            onFit={handleFitMap}
            onView={handleViewMode}
            onEdit={handleEditMode}
            onUndo={handleUndo}
            onRedo={handleRedo}
          />
        ) : null}

        {!hasAnyMap || (mode === "setup" && mapState?.draft_map && !mapState?.published_map) ? (
          <LocationMapSetupPanel
            hasAnyMap={hasVisibleOrManageableMap}
            canManage={canManage}
            zoneCount={mapState?.zones?.length || 0}
            saving={saving}
            savingAction={savingAction}
            onContinue={() => {
              setMode("edit");
              setPreviewDraft(true);
            }}
            onPreview={handlePreviewDraft}
            onPublish={handlePublish}
            onCreateFromZones={handleCreateFromZones}
            onCreateBlank={handleCreateBlank}
          />
        ) : (
          <>
            <LocationMapCanvas
              mode={mode}
              objects={objects}
              filters={filters}
              mapSize={mapSize}
              zoom={zoom}
              selectedObjectKey={selectedObjectKey}
              mapItems={mapItems}
              username={username}
              svgRef={svgRef}
              dragState={dragState}
              editingLocked={saving}
              hiddenAreaCount={hiddenAreaCount}
              onAddObject={handleAddObject}
              setDragState={setDragState}
              setSelectedObjectKey={setSelectedObjectKey}
              remember={remember}
              updateObjects={updateObjects}
              expandMapToFitObject={expandMapToFitObject}
              onShowZones={() =>
                setFilters((current) => ({
                  ...current,
                  showZones: true,
                }))
              }
              onShowHiddenAreas={handleShowHiddenAreas}
            />
            <LocationMapBottomSheet
              mode={mode}
              canManage={canManage}
              filters={filters}
              setFilters={setFilters}
              layersOpen={layersOpen}
              setLayersOpen={setLayersOpen}
              selectedObject={selectedObject}
              mapObjects={objects}
              selectedZoneItems={selectedZoneItems}
              visibleAssignedItemCount={visibleAssignedItemCount}
              visibleUnmappedItems={visibleUnmappedItems}
              unmappedItemCount={unmappedItemCount}
              hiddenAreaCount={hiddenAreaCount}
              saving={saving}
              savingAction={savingAction}
              hasUnsavedChanges={hasUnsavedChanges}
              mapState={mapState}
              onAddObject={handleAddObject}
              onSaveDraft={handleSaveDraft}
              onPublish={handlePublish}
              onObjectField={handleObjectField}
              onZoneLinkChange={handleZoneLinkChange}
              onDuplicateObject={handleDuplicateObject}
              onDeleteObject={requestDeleteObject}
              onShowHiddenAreas={handleShowHiddenAreas}
              onClearSelection={() => setSelectedObjectKey(null)}
              onSelectZoneItem={setBuyModalItem}
              onSelectUnmappedItem={setBuyModalItem}
            />
          </>
        )}
      </main>

      <LocationMapDialogs
        buyModalItem={buyModalItem}
        buyModalItems={buyModalItems}
        onBuyNavigate={handleMapBuyNavigate}
        onBuyCancel={handleMapBuyCancel}
        onBuyConfirm={handleMapBuyConfirm}
        pendingDeleteObject={pendingDeleteObject}
        onDeleteClose={() => setPendingDeleteObject(null)}
        onDeleteConfirm={handleDeleteObject}
        pendingLeaveTarget={pendingLeaveTarget}
        onLeaveClose={clearPendingLeave}
        onLeaveConfirm={confirmPendingLeave}
      />
    </div>
  );
}
