import { Suspense, type MutableRefObject, type ReactNode } from 'react';

import type {
  ActualListing,
  FeatureFilters,
  FeatureMeta,
  POI,
  PostcodeGeometry,
  ViewState,
} from '../../../types';
import type { useMapData } from '../../../hooks/useMapData';
import type { TravelTimeEntry } from '../../../hooks/useTravelTime';
import type { OverlayId } from '../../../lib/overlays';
import type { SearchedLocation } from '../LocationSearch';
import MobileBottomSheet from '../MobileBottomSheet';
import { MapPinIcon } from '../../ui/icons/MapPinIcon';
import { EyeIcon } from '../../ui/icons/EyeIcon';
import { IndeterminateProgressBar } from '../../ui/IndeterminateProgressBar';
import type { MapFlyTo } from './types';
import { MapFallback, PaneFallback } from './Fallbacks';
import { LoadingOverlay } from './LoadingOverlay';
import { Map, MobileDrawer } from './lazyComponents';

type MapData = ReturnType<typeof useMapData>;
type RightPaneTab = 'properties' | 'area';

interface MobileMapPageProps {
  initialLoading: boolean;
  mapData: MapData;
  pois: POI[];
  activeOverlays: Set<OverlayId>;
  mapViewFeature: string | null;
  filterRange: [number, number] | null;
  viewSource: 'drag' | 'eye' | null;
  onCancelPin: () => void;
  features: FeatureMeta[];
  selectedHexagonId: string | null;
  hoveredHexagonId: string | null;
  onHexagonClick: (id: string, isPostcode?: boolean, geometry?: PostcodeGeometry) => void;
  onHexagonHover: (h3: string | null, x?: number, y?: number) => void;
  initialViewState: ViewState;
  flyToRef: MutableRefObject<MapFlyTo | null>;
  theme: 'light' | 'dark';
  filters: FeatureFilters;
  selectedPostcodeGeometry: PostcodeGeometry | null;
  onLocationSearched: (location: SearchedLocation | null) => void;
  onCurrentLocationFound: (lat: number, lng: number) => void;
  currentLocation: { lat: number; lng: number } | null;
  actualListings: ActualListing[];
  travelTimeEntries: TravelTimeEntry[];
  bottomScreenInset: number;
  onBottomSheetCoveredHeightChange: (height: number) => void;
  mobileDrawerOpen: boolean;
  onMobileDrawerClose: () => void;
  onMobileDrawerPanelRectChange: (rect: DOMRectReadOnly) => void;
  rightPaneTab: RightPaneTab;
  onMobileDrawerTabChange: (tab: RightPaneTab) => void;
  poiPaneOpen: boolean;
  onTogglePoiPane: () => void;
  poiButtonLabel: string;
  poiPane: ReactNode;
  overlayPaneOpen: boolean;
  onToggleOverlayPane: () => void;
  overlayPane: ReactNode;
  filtersPane: ReactNode;
  mobileLegend: ReactNode;
  renderAreaPane: () => ReactNode;
  renderPropertiesPane: () => ReactNode;
  toasts: ReactNode;
  upgradeModal: ReactNode;
  editingBar?: ReactNode;
}

export function MobileMapPage({
  initialLoading,
  mapData,
  pois,
  activeOverlays,
  mapViewFeature,
  filterRange,
  viewSource,
  onCancelPin,
  features,
  selectedHexagonId,
  hoveredHexagonId,
  onHexagonClick,
  onHexagonHover,
  initialViewState,
  flyToRef,
  theme,
  filters,
  selectedPostcodeGeometry,
  onLocationSearched,
  onCurrentLocationFound,
  currentLocation,
  actualListings,
  travelTimeEntries,
  bottomScreenInset,
  onBottomSheetCoveredHeightChange,
  mobileDrawerOpen,
  onMobileDrawerClose,
  onMobileDrawerPanelRectChange,
  rightPaneTab,
  onMobileDrawerTabChange,
  poiPaneOpen,
  onTogglePoiPane,
  poiButtonLabel,
  poiPane,
  overlayPaneOpen,
  onToggleOverlayPane,
  overlayPane,
  filtersPane,
  mobileLegend,
  renderAreaPane,
  renderPropertiesPane,
  toasts,
  upgradeModal,
  editingBar,
}: MobileMapPageProps) {
  return (
    <div className="flex-1 overflow-hidden relative">
      <LoadingOverlay show={initialLoading} />

      <div className="absolute inset-0">
        <IndeterminateProgressBar show={mapData.loading && !initialLoading} />
        <Suspense fallback={<MapFallback />}>
          <Map
            data={mapData.data}
            postcodeData={mapData.postcodeData}
            usePostcodeView={mapData.usePostcodeView}
            pois={pois}
            activeOverlays={activeOverlays}
            onViewChange={mapData.handleViewChange}
            viewFeature={mapViewFeature}
            colorRange={mapData.colorRange}
            filterRange={filterRange}
            viewSource={viewSource}
            onCancelPin={onCancelPin}
            onResetPreviewScale={mapData.handleResetPreviewScale}
            canResetPreviewScale={mapData.canResetPreviewScale}
            features={features}
            selectedHexagonId={selectedHexagonId}
            hoveredHexagonId={hoveredHexagonId}
            onHexagonClick={onHexagonClick}
            onHexagonHover={onHexagonHover}
            initialViewState={initialViewState}
            flyToRef={flyToRef}
            theme={theme}
            filters={filters}
            selectedPostcodeGeometry={selectedPostcodeGeometry}
            onLocationSearched={onLocationSearched}
            onCurrentLocationFound={onCurrentLocationFound}
            currentLocation={currentLocation}
            actualListings={actualListings}
            bounds={mapData.bounds}
            hideLegend
            hideLocationSearch={mobileDrawerOpen && !!selectedHexagonId}
            travelTimeEntries={travelTimeEntries}
            bottomScreenInset={bottomScreenInset}
          />
        </Suspense>
      </div>

      <div className="absolute right-3 top-3 z-20 flex flex-col gap-2">
        <button
          onClick={onToggleOverlayPane}
          className={`rounded-lg bg-white p-2 shadow-lg dark:bg-warm-800 ${overlayPaneOpen ? 'text-teal-600 dark:text-teal-400' : 'text-warm-500 hover:text-teal-600 dark:text-warm-400 dark:hover:text-teal-400'}`}
          aria-label="Overlays"
        >
          <EyeIcon className="h-5 w-5" filled={overlayPaneOpen} />
        </button>
        <button
          onClick={onTogglePoiPane}
          className={`rounded-lg bg-white p-2 shadow-lg dark:bg-warm-800 ${poiPaneOpen ? 'text-teal-600 dark:text-teal-400' : 'text-warm-500 hover:text-teal-600 dark:text-warm-400 dark:hover:text-teal-400'}`}
          aria-label={poiButtonLabel}
        >
          <MapPinIcon className="h-5 w-5" />
        </button>
      </div>

      {overlayPaneOpen && (
        <div className="absolute top-24 right-3 left-3 z-20 flex h-[220px] min-h-0 flex-col overflow-hidden rounded-lg border border-warm-200 bg-white shadow-xl dark:border-warm-700 dark:bg-warm-900">
          {overlayPane}
        </div>
      )}

      {poiPaneOpen && (
        <div className="absolute top-24 right-3 left-3 z-20 flex h-[45dvh] min-h-0 flex-col overflow-hidden rounded-lg border border-warm-200 bg-white shadow-xl dark:border-warm-700 dark:bg-warm-900">
          {poiPane}
        </div>
      )}

      <MobileBottomSheet
        legend={mobileLegend}
        editingBar={editingBar}
        onCoveredHeightChange={onBottomSheetCoveredHeightChange}
      >
        {filtersPane}
      </MobileBottomSheet>

      {mobileDrawerOpen && selectedHexagonId && (
        <Suspense fallback={<PaneFallback />}>
          <MobileDrawer
            onClose={onMobileDrawerClose}
            renderArea={renderAreaPane}
            renderProperties={renderPropertiesPane}
            tab={rightPaneTab}
            onPanelRectChange={onMobileDrawerPanelRectChange}
            onTabChange={onMobileDrawerTabChange}
          />
        </Suspense>
      )}

      {toasts}
      {upgradeModal}
    </div>
  );
}
