"use client";

import {
	Circle,
	MapContainer,
	Marker,
	Polyline,
	Popup,
	TileLayer,
	useMapEvents,
} from "react-leaflet";

import "leaflet/dist/leaflet.css";
import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css";
import "leaflet-defaulticon-compatibility";
import { Home } from "lucide-react";
import { useState } from "react";
import { Marker as CustomMarker } from "~/components/map/custom_marker";
import MapMarker from "~/components/map/map_marker";
import { cn } from "~/lib/utils";

type LatLon = {
	lat: number;
	lng: number;
	alt?: number;
};
type posData = {
	pos: LatLon;
	popupTxt?: string;
	onClick?: () => void;
	markerTxt?: string;
};

type GroupProps = {
	isGroup: true;
	groupData: posData[];
};

type SingleProps = {
	isGroup?: false;
	groupData?: never;
};

type MarkerType = "precise" | "circle" | "price" | "home";

type MapProps = {
	posix: posData;
	autocenter?: boolean;
	zoom?: number;
	markerType: MarkerType;
	markerRadius?: number;
	scrollWheelZoom?: boolean;
	width?: string;
	height?: string;
	onMapClick?: () => void;
	isMeasuring?: boolean;
} & (GroupProps | SingleProps);

const defaults = {
	height: "500px",
	width: "500px",
	zoom: 15,
};

const MedianPoint = (pos: posData[]) => {
	const lat = pos.map((p) => p.pos.lat).reduce((a, b) => a + b) / pos.length;
	const lng = pos.map((p) => p.pos.lng).reduce((a, b) => a + b) / pos.length;
	return { lat, lng };
};

const MarkerComp = ({
	pos,
	markerType,
	markerRadius,
}: {
	pos: posData;
	markerType: MarkerType;
	markerRadius?: number;
}) => {
	switch (markerType) {
		case "price":
			return (
				<CustomMarker
					eventHandlers={pos.onClick && { click: pos.onClick }}
					icon={
						<MapMarker
							color="primary"
							label={
								<span className="inline-block whitespace-nowrap">
									{pos.markerTxt}
								</span>
							}
							size="sm"
						/>
					}
					position={pos.pos}
					title={pos.markerTxt}
				>
					{pos.popupTxt && <Popup>{pos.popupTxt}</Popup>}
				</CustomMarker>
			);

		case "precise":
			return (
				<Marker
					eventHandlers={pos.onClick && { click: pos.onClick }}
					position={pos.pos}
					title={pos.markerTxt}
				>
					{pos.popupTxt && <Popup>{pos.popupTxt}</Popup>}
				</Marker>
			);
		case "circle":
			return (
				<Circle
					center={pos.pos}
					eventHandlers={pos.onClick && { click: pos.onClick }}
					pathOptions={{ color: "red" }}
					radius={markerRadius || 100}
				>
					{pos.popupTxt && <Popup>{pos.popupTxt}</Popup>}
				</Circle>
			);
		case "home":
			return (
				<>
					<Circle
						center={pos.pos}
						eventHandlers={pos.onClick && { click: pos.onClick }}
						fillOpacity={1}
						pathOptions={{ color: "#ec4899" }}
						radius={markerRadius || 100}
					>
						{pos.popupTxt && <Popup>{pos.popupTxt}</Popup>}
					</Circle>
					<CustomMarker
						eventHandlers={pos.onClick && { click: pos.onClick }}
						icon={
							<div className="relative flex size-10 items-center justify-center rounded-full bg-pink-500 p-2">
								<Home className="absolute size-3/4 stroke-white" />
							</div>
						}
						position={pos.pos}
						title={pos.markerTxt}
					>
						{pos.popupTxt && <Popup>{pos.popupTxt}</Popup>}
					</CustomMarker>
				</>
			);
		default:
			throw new Error(`Invalid marker type: ${markerType satisfies never}`);
	}
};

function getDistanceInKm(pos1: LatLon, pos2: LatLon) {
	const R = 6371; // Radius of the earth in km
	const dLat = deg2rad(pos2.lat - pos1.lat);
	const dLon = deg2rad(pos2.lng - pos1.lng);

	const a =
		Math.sin(dLat / 2) * Math.sin(dLat / 2) +
		Math.cos(deg2rad(pos1.lat)) *
			Math.cos(deg2rad(pos2.lat)) *
			Math.sin(dLon / 2) *
			Math.sin(dLon / 2);
	const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
	const distance = R * c; // Distance in km
	return distance;
}

function deg2rad(deg: number) {
	return deg * (Math.PI / 180);
}

const DistanceMarker = ({ pos, posix }: { pos: LatLon; posix: posData }) => {
	const distanceKm = getDistanceInKm(pos, posix.pos);
	return (
		<>
			<CustomMarker
				icon={
					<MapMarker
						color="orange"
						label={
							<span className="inline-block whitespace-nowrap">
								~{distanceKm.toFixed(2)} km
							</span>
						}
						size="sm"
					/>
				}
				position={pos}
				title={"Distanza"}
			/>

			<Polyline
				pathOptions={{
					color: "#2563eb", // Primary Blue (Tailwind blue-600)
					weight: 4,
					dashArray: "15, 10", // Creates the "Ruler" dashed effect (15px line, 10px gap)
					opacity: 0.7,
					lineCap: "round", // Makes the ends of the dashes rounded
				}}
				positions={[posix.pos, pos]}
			/>
		</>
	);
};

const MapComp = ({
	posix,
	autocenter,
	zoom = defaults.zoom,
	markerType,
	markerRadius,
	scrollWheelZoom = false,
	width = defaults.width,
	height = defaults.height,
	isGroup,
	groupData,
	onMapClick,
	isMeasuring,
}: MapProps) => {
	const [measuringPos, setMeasuringPos] = useState<LatLon | null>(null);
	const APIs = () => {
		useMapEvents({
			click: (e) => {
				if (isMeasuring) {
					setMeasuringPos(e.latlng);
					return;
				}
				if (onMapClick) {
					onMapClick();
				}
			},
		});
		return null;
	};

	const hashKey = JSON.stringify(
		groupData ? groupData.map((p) => p.pos) : posix.pos,
	);

	return (
		<MapContainer
			center={
				autocenter ? MedianPoint(isGroup ? groupData : [posix]) : posix.pos
			}
			className={cn("")}
			key={hashKey}
			scrollWheelZoom={scrollWheelZoom}
			style={{
				borderRadius: "8px",
				height: height,
				width: width,
			}}
			zoom={zoom}
		>
			<APIs />
			<TileLayer
				attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
				//url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
				url="/api/tiles/{s}/{z}/{x}/{y}"
			/>

			{isGroup ? (
				groupData.map((pos, i) => (
					<MarkerComp
						// biome-ignore lint/suspicious/noArrayIndexKey: <index is acceptable here>
						key={i}
						markerRadius={markerRadius}
						markerType={markerType}
						pos={pos}
					/>
				))
			) : (
				<MarkerComp
					markerRadius={markerRadius}
					markerType={markerType}
					pos={posix}
				/>
			)}
			{isMeasuring && measuringPos && (
				<DistanceMarker pos={measuringPos} posix={posix} />
			)}
		</MapContainer>
	);
};

export default MapComp;

/*
const PuntiInteresse: {
  title: string;
  lat: number;
  lng: number;
  icon: IconType;
}[] = [
  {
    title: "PIAZZA LIBERTA’",
    lat: 45.766706,
    lng: 11.733919,
    icon: "milestone",
  },
  { title: "PONTE VECCHIO", lat: 45.76752, lng: 11.731148, icon: "milestone" },
  { title: "INFOALLOGGI", lat: 45.764886, lng: 11.736019, icon: "info" },
  { title: "PRATO 1", lat: 45.770066, lng: 11.736306, icon: "parking" },
  { title: "PRATO 2", lat: 45.771495, lng: 11.734107, icon: "parking" },
  {
    title: "STAZIONE FERROVIARIA/BUS",
    lat: 45.766709,
    lng: 11.741204,
    icon: "milestone",
  },
  { title: "GIARDINI PAROLINI", lat: 45.764804, lng: 11.738355, icon: "park" },
  { title: "BIBLIOTECA", lat: 45.765801, lng: 11.735987, icon: "school" },
  { title: "CENTRO STUDIO", lat: 45.754266, lng: 11.733066, icon: "school" },
  { title: "OSPEDALE", lat: 45.747444, lng: 11.744371, icon: "cross" },
  {
    title: "PALARENA CMP",
    lat: 45.747374,
    lng: 11.740302,
    icon: "entertainment",
  },
  { title: "PONTE NUOVO", lat: 45.764594, lng: 11.729995, icon: "milestone" },
  { title: "OSSARIO ", lat: 45.763568, lng: 11.733449, icon: "milestone" },
  { title: "CINEMA METROPOLIS", lat: 45.742997, lng: 11.735622, icon: "film" },
  {
    title: "CENTRO COMMERCIALE GRIFONE",
    lat: 45.744988,
    lng: 11.751847,
    icon: "cart",
  },
  {
    title: "CENTRO COMMERCIALE EMISFERO",
    lat: 45.742368,
    lng: 11.728874,
    icon: "cart",
  },
  {
    title: "SUPERMERCATO Alì s. vito",
    lat: 45.775167,
    lng: 11.750929,
    icon: "cart",
  },
  {
    title: "SUPERMERCATO Alì cà baroncello ",
    lat: 45.758659,
    lng: 11.751037,
    icon: "cart",
  },
  {
    title: "CONAD via passalacqua",
    lat: 45.771366,
    lng: 11.742604,
    icon: "cart",
  },
  {
    title: "CONAD  VIALE PECORI GIRARDI",
    lat: 45.764649,
    lng: 11.720416,
    icon: "cart",
  },
  {
    title: "BIOSAPORI VIALE DE GASPERI",
    lat: 45.761377,
    lng: 11.732186,
    icon: "cart",
  },
  { title: "SUPERMERCATO ALDI ", lat: 45.743694, lng: 11.755435, icon: "cart" },
  {
    title: "SUPERMERCATO TOSANO",
    lat: 45.764982,
    lng: 11.766572,
    icon: "cart",
  },
  {
    title: "POSTE CENTRALI BASSANO",
    lat: 45.762758,
    lng: 11.735091,
    icon: "mail",
  },
  { title: "POSTE VIA ANGARANO", lat: 45.767573, lng: 11.726599, icon: "mail" },
];
*/
