'use client';
import { FunctionComponent, MouseEvent as ReactMouseEvent, PointerEvent as ReactPointerEvent, useRef, useState } from 'react';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import AppIcon from '@/components/common/AppIcon';
import { IRAN_CENTROID } from '@/services/geography/constants';
import type { LatLng } from '@/services/addresses/types';

export interface AddressMapPickerProps {
  value: LatLng | null;
  onChange: (value: LatLng) => void;
  /** Centre of the picker's viewport — the chosen city's centroid, or the Iran centroid. */
  center?: LatLng;
  helperText: string;
  latLabel: string;
  lngLabel: string;
  error?: boolean;
  errorText?: string;
}

// Half-degree span each side of the centre (~±6 km) — enough precision for the later EVV check
// while keeping the whole stand-in viewport around one city.
const SPAN = 0.06;
const clamp01 = (n: number) => Math.min(1, Math.max(0, n));
const round6 = (n: number) => Math.round(n * 1e6) / 1e6;

/**
 * Lightweight **map-pin picker stand-in** — a draggable/tappable marker panel that emits real
 * `{ latitude, longitude }`. It is NOT a real map (no Neshan/Google tiles), only a bounded
 * canvas mapping the pointer position to coordinates around the chosen city's centroid, behind a
 * small component boundary so a real map drops in later without touching the address form. The
 * picked coordinates are what the create/update request sends; the pin only refines coordinates —
 * the bookable geography is still the region dropdown choice.
 * @component AddressMapPicker
 */
const AddressMapPicker: FunctionComponent<AddressMapPickerProps> = ({
  value,
  onChange,
  center = IRAN_CENTROID,
  helperText,
  latLabel,
  lngLabel,
  error = false,
  errorText,
}) => {
  const mapRef = useRef<HTMLDivElement>(null);
  const [dragging, setDragging] = useState(false);

  // Fraction [0,1] across the canvas → coordinates. x: west→east (left→right); y: north→south (top→bottom).
  const fractionToLatLng = (fx: number, fy: number): LatLng => ({
    latitude: round6(center.latitude + SPAN - clamp01(fy) * 2 * SPAN),
    longitude: round6(center.longitude - SPAN + clamp01(fx) * 2 * SPAN),
  });

  // Inverse — coordinates → percent offsets for the marker, plus the centering transform. All applied
  // via inline `style` (not `sx`) so the RTL stylis plugin can't mirror them: it flips physical `left`
  // AND inverts the X of `transform: translate(...)`, either of which would offset the pin from its
  // click point on the default (fa/RTL) locale. Inline style bypasses the emotion cache entirely.
  const markerStyle = (v: LatLng) => ({
    left: `${clamp01((v.longitude - (center.longitude - SPAN)) / (2 * SPAN)) * 100}%`,
    top: `${clamp01((center.latitude + SPAN - v.latitude) / (2 * SPAN)) * 100}%`,
    transform: 'translate(-50%, -100%)',
  });

  const place = (clientX: number, clientY: number) => {
    const rect = mapRef.current?.getBoundingClientRect();
    // jsdom / zero-size layouts report a 0×0 rect — fall back to the centre so a tap still resolves.
    const fx = rect && rect.width ? (clientX - rect.left) / rect.width : 0.5;
    const fy = rect && rect.height ? (clientY - rect.top) / rect.height : 0.5;
    onChange(fractionToLatLng(fx, fy));
  };

  // A tap places via `click` (reliable everywhere); a drag places via pointer moves while held.
  const handleClick = (event: ReactMouseEvent<HTMLDivElement>) => place(event.clientX, event.clientY);
  const handlePointerDown = () => setDragging(true);
  const handlePointerMove = (event: ReactPointerEvent<HTMLDivElement>) => {
    if (dragging) place(event.clientX, event.clientY);
  };
  const stopDragging = () => setDragging(false);

  return (
    <Stack sx={{ gap: 1 }}>
      <Box
        ref={mapRef}
        dir="ltr"
        role="application"
        aria-label={helperText}
        onClick={handleClick}
        onPointerDown={handlePointerDown}
        onPointerMove={handlePointerMove}
        onPointerUp={stopDragging}
        onPointerLeave={stopDragging}
        sx={{
          position: 'relative',
          height: 220,
          borderRadius: 2,
          border: '1px solid',
          borderColor: error ? 'var(--bal-error)' : 'divider',
          cursor: 'crosshair',
          overflow: 'hidden',
          touchAction: 'none',
          bgcolor: 'var(--bal-primary-soft)',
          backgroundImage:
            'linear-gradient(var(--bal-divider) 1px, transparent 1px), linear-gradient(90deg, var(--bal-divider) 1px, transparent 1px)',
          backgroundSize: '28px 28px',
        }}
      >
        {value ? (
          <Box sx={{ position: 'absolute', inset: 0 }}>
            <Box
              style={markerStyle(value)}
              sx={{
                position: 'absolute',
                color: 'var(--bal-primary)',
                filter: 'drop-shadow(0 1px 2px rgba(0,0,0,0.35))',
                pointerEvents: 'none',
              }}
            >
              <AppIcon icon="location" size={32} color="var(--bal-primary)" />
            </Box>
          </Box>
        ) : (
          <Stack sx={{ position: 'absolute', inset: 0, alignItems: 'center', justifyContent: 'center', gap: 0.5, pointerEvents: 'none' }}>
            <AppIcon icon="location" size={28} color="var(--bal-text-secondary)" />
            <Typography variant="caption" sx={{ color: 'text.secondary' }}>
              {helperText}
            </Typography>
          </Stack>
        )}
      </Box>

      {error && errorText ? (
        <Typography variant="caption" sx={{ color: 'var(--bal-error)' }}>
          {errorText}
        </Typography>
      ) : (
        <Typography variant="caption" sx={{ color: 'text.secondary' }}>
          {helperText}
        </Typography>
      )}

      {value ? (
        <Stack direction="row" dir="ltr" sx={{ gap: 2, alignSelf: 'flex-start' }}>
          <Typography variant="caption" sx={{ color: 'text.secondary' }}>
            {latLabel}: {value.latitude.toFixed(5)}
          </Typography>
          <Typography variant="caption" sx={{ color: 'text.secondary' }}>
            {lngLabel}: {value.longitude.toFixed(5)}
          </Typography>
        </Stack>
      ) : null}
    </Stack>
  );
};

export default AddressMapPicker;
