"use client";

/**
 * OfficeMap
 * ---------------------------------------------------------------------------
 * Client-only Leaflet satellite map (Esri World Imagery) rendering the three
 * Doormile office markers, plus a row of "jump to office" buttons that fly the
 * map to a selected office's coordinates and open its popup.
 *
 * The map centers with a North latitude offset to keep markers lower in the viewport,
 * avoiding collisions with the navigation tabs. Popups are compact and styled like
 * clean business cards.
 */

import "leaflet/dist/leaflet.css";
import styles from "./OfficeMap.module.css";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import L from "leaflet";
import { MapContainer, Marker, Popup, TileLayer, ZoomControl, useMap } from "react-leaflet";

import {
  LatLng,
  ESRI_WORLD_IMAGERY,
  HQ_OFFICE,
  MAP_FOCUS_ZOOM,
  MAP_INITIAL_CENTER,
  MAP_INITIAL_ZOOM,
  OFFICE_LOCATIONS,
} from "./offices";

type MapStatus = "loading" | "ready" | "error";

/** A request to focus a specific office. `nonce` lets the same office be re-selected. */
type FocusTarget = { id: string; nonce: number };

/**
 * Build a branded SVG pin. The headquarters pin is larger, carries a red glow
 * and a soft pulse ring, and sits above every other marker.
 */
function createMarkerIcon(isHeadquarters: boolean): L.DivIcon {
  if (isHeadquarters) {
    return L.divIcon({
      className: styles.markerIconHq,
      html: `
        <span class="${styles.pinPulse}" aria-hidden="true"></span>
        <svg width="40" height="52" viewBox="0 0 30 40" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false">
          <path d="M15 0C6.72 0 0 6.72 0 15c0 10.5 13.06 23.86 13.62 24.42a1.95 1.95 0 0 0 2.76 0C16.94 38.86 30 25.5 30 15 30 6.72 23.28 0 15 0Z" fill="#C01227"/>
          <path d="M15 1.5C7.54 1.5 1.5 7.54 1.5 15c0 9.6 12.3 22.4 12.83 22.94a.95.95 0 0 0 1.34 0C16.2 37.4 28.5 24.6 28.5 15 28.5 7.54 22.46 1.5 15 1.5Z" fill="none" stroke="#ffffff" stroke-width="1.2" stroke-opacity="0.9"/>
          <circle cx="15" cy="15" r="5.4" fill="#ffffff"/>
        </svg>
      `,
      iconSize: [40, 52],
      iconAnchor: [20, 52],
      popupAnchor: [0, -52], // Anchored to top tip of pin
    });
  }

  return L.divIcon({
    className: styles.markerIcon,
    html: `
      <svg width="30" height="40" viewBox="0 0 30 40" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false">
        <path d="M15 0C6.72 0 0 6.72 0 15c0 10.5 13.06 23.86 13.62 24.42a1.95 1.95 0 0 0 2.76 0C16.94 38.86 30 25.5 30 15 30 6.72 23.28 0 15 0Z" fill="#C01227"/>
        <path d="M15 1.5C7.54 1.5 1.5 7.54 1.5 15c0 9.6 12.3 22.4 12.83 22.94a.95.95 0 0 0 1.34 0C16.2 37.4 28.5 24.6 28.5 15 28.5 7.54 22.46 1.5 15 1.5Z" fill="none" stroke="#ffffff" stroke-width="1.2" stroke-opacity="0.85"/>
        <circle cx="15" cy="15" r="5.4" fill="#ffffff"/>
      </svg>
    `,
    iconSize: [30, 40],
    iconAnchor: [15, 40],
    popupAnchor: [0, -40], // Anchored to top tip of pin
  });
}

/**
 * Imperative map effects that need the Leaflet instance:
 *  - keep the viewport sized correctly across resizes / lazy reveals
 *  - snap to the offset HQ on first paint, fly thereafter and open popups.
 */
function MapController({
  focus,
  markerRefs,
}: {
  focus: FocusTarget | null;
  markerRefs: React.RefObject<Record<string, L.Marker>>;
}) {
  const map = useMap();
  const didInit = useRef(false);

  // Keep the map correctly sized on container resize / lazy reveal.
  useEffect(() => {
    const container = map.getContainer();
    let raf = 0;
    const observer = new ResizeObserver(() => {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => map.invalidateSize());
    });
    observer.observe(container);
    return () => {
      cancelAnimationFrame(raf);
      observer.disconnect();
    };
  }, [map]);

  // React to the focused office: snap on first paint, fly thereafter.
  useEffect(() => {
    if (!focus) return;
    const office = OFFICE_LOCATIONS.find((item) => item.id === focus.id);
    if (!office) return;

    const openPopup = () => markerRefs.current[office.id]?.openPopup();

    // Offset the center slightly North so the marker sits lower in the viewport,
    // preventing the popup card from colliding with the top controls.
    const offsetLatitude = 0.022;
    const centeredPosition: LatLng = [office.position[0] + offsetLatitude, office.position[1]];

    if (!didInit.current) {
      didInit.current = true;
      map.invalidateSize();
      map.setView(centeredPosition, MAP_FOCUS_ZOOM, { animate: false });
      const raf = requestAnimationFrame(openPopup);
      return () => cancelAnimationFrame(raf);
    }

    map.flyTo(centeredPosition, MAP_FOCUS_ZOOM, { duration: 1.1 });
    map.once("moveend", openPopup);
    return () => {
      map.off("moveend", openPopup);
    };
  }, [map, focus, markerRefs]);

  return null;
}

export default function OfficeMap() {
  const icon = useMemo(() => createMarkerIcon(false), []);
  const hqIcon = useMemo(() => createMarkerIcon(true), []);
  const markerRefs = useRef<Record<string, L.Marker>>({});

  // Default to the headquarters.
  const [focus, setFocus] = useState<FocusTarget | null>({ id: HQ_OFFICE.id, nonce: 0 });
  const focusOffice = useCallback((id: string) => {
    setFocus((prev) => ({ id, nonce: (prev?.nonce ?? 0) + 1 }));
  }, []);

  const [hoveredOfficeId, setHoveredOfficeId] = useState<string | null>(null);

  // Restore the focused office popup when mouse leaves other markers.
  useEffect(() => {
    if (hoveredOfficeId === null && focus?.id) {
      markerRefs.current[focus.id]?.openPopup();
    }
  }, [hoveredOfficeId, focus]);

  const [status, setStatus] = useState<MapStatus>("loading");
  const loadedRef = useRef(false);
  const errorCountRef = useRef(0);

  const handleTileLoad = useCallback(() => {
    loadedRef.current = true;
    setStatus("ready");
  }, []);

  const handleTileError = useCallback(() => {
    errorCountRef.current += 1;
    if (!loadedRef.current && errorCountRef.current >= 6) setStatus("error");
  }, []);

  useEffect(() => {
    const timeout = window.setTimeout(() => {
      if (!loadedRef.current) setStatus("error");
    }, 12_000);
    return () => window.clearTimeout(timeout);
  }, []);

  return (
    <div className={styles.root} role="region" aria-label="Map of Doormile office locations">
      {/* Semantic, always-available fallback for assistive tech + no-JS/SEO. */}
      <ul className={styles.srOnly}>
        {OFFICE_LOCATIONS.map((office) => (
          <li key={office.id}>
            {office.name} — latitude {office.position[0]}, longitude {office.position[1]}
          </li>
        ))}
      </ul>

      {/* Jump-to-office navigation buttons. */}
      <div className={styles.controls} role="group" aria-label="Jump to an office location">
        {OFFICE_LOCATIONS.map((office) => {
          const isActive = focus?.id === office.id;
          return (
            <button
              key={office.id}
              type="button"
              className={`${styles.controlBtn} ${isActive ? styles.controlBtnActive : ""} ${
                office.isHeadquarters ? styles.controlBtnHq : ""
              }`}
              aria-pressed={isActive}
              aria-label={`Show ${office.name} on the map`}
              onClick={() => focusOffice(office.id)}
            >
              {office.city}
            </button>
          );
        })}
      </div>

      <MapContainer
        className={styles.map}
        center={MAP_INITIAL_CENTER}
        zoom={MAP_INITIAL_ZOOM}
        scrollWheelZoom={false}
        zoomControl={false}
        attributionControl={false}
        worldCopyJump
      >
        {/* Keep zoom controls clear of the top-row buttons. */}
        <ZoomControl position="bottomleft" />

        <TileLayer
          url={ESRI_WORLD_IMAGERY.url}
          attribution={ESRI_WORLD_IMAGERY.attribution}
          maxZoom={ESRI_WORLD_IMAGERY.maxZoom}
          updateWhenIdle
          keepBuffer={2}
          eventHandlers={{ load: handleTileLoad, tileerror: handleTileError }}
        />

        {OFFICE_LOCATIONS.map((office) => {
          const isFocused = focus?.id === office.id;


          return (
            <Marker
              key={office.id}
              position={office.position}
              icon={office.isHeadquarters ? hqIcon : icon}
              zIndexOffset={office.isHeadquarters ? 1000 : 0}
              keyboard
              title={office.name}
              alt={office.name}
              eventHandlers={{
                click: () => focusOffice(office.id),
                mouseover: (event) => {
                  setHoveredOfficeId(office.id);
                  event.target.openPopup();
                },
                mouseout: (event) => {
                  setHoveredOfficeId(null);
                  if (focus?.id !== office.id) {
                    event.target.closePopup();
                  }
                },
              }}
              ref={(instance) => {
                if (instance) markerRefs.current[office.id] = instance;
              }}
            >
              <Popup
                className={styles.popup}
                autoPan={isFocused}
                autoPanPadding={[25, 25]}
                closeButton={false}
                minWidth={240}
                maxWidth={290}
              >
                <div className={styles.card}>
                  <div className={styles.cardHeader}>
                    <span className={styles.cardIcon} aria-hidden="true">📍</span>
                    <h4 className={styles.cardTitle}>{office.city} Office</h4>
                  </div>
                  <div className={styles.cardBody}>
                    {office.address.map((line, idx) => (
                      <p key={idx} className={styles.addressLine}>
                        {line}
                      </p>
                    ))}
                  </div>
                </div>
              </Popup>
            </Marker>
          );
        })}

        <MapController focus={focus} markerRefs={markerRefs} />
      </MapContainer>

      {status === "error" && (
        <div className={styles.errorOverlay} role="alert">
          <p className={styles.errorTitle}>Map could not be loaded</p>
          <p className={styles.errorText}>
            Please check your connection. Our offices are located in:
          </p>
          <ul className={styles.errorList}>
            {OFFICE_LOCATIONS.map((office) => (
              <li key={office.id}>{office.name}</li>
            ))}
          </ul>
        </div>
      )}
    </div>
  );
}
