import { useEffect, useRef } from 'react';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';

type MapPoint = {
    id: string | number;
    lat: number;
    lng: number;
    title: string;
    description?: string;
    type?: 'customer' | 'visit' | 'order';
};

type MapArea = {
    id: string | number;
    name: string;
    code?: string;
    lat?: number | null;
    lng?: number | null;
    radius_meters?: number | null;
};

type Props = {
    points?: MapPoint[];
    areas?: MapArea[];
    height?: number;
    center?: [number, number];
    zoom?: number;
};

const icon = (type: MapPoint['type']) =>
    L.divIcon({
        className: '',
        html: `<div style="width:30px;height:30px;border-radius:999px;border:3px solid white;box-shadow:0 2px 8px rgba(0,0,0,.3);display:grid;place-items:center;background:${type === 'visit' ? '#2563eb' : type === 'order' ? '#16a34a' : '#f59e0b'};color:white;font-size:13px;font-weight:800">${type === 'visit' ? 'V' : type === 'order' ? 'O' : 'C'}</div>`,
        iconSize: [30, 30],
        iconAnchor: [15, 15],
    });

export default function CrmOsmMap({ points = [], areas = [], height = 400, center = [0.5402, 123.0595], zoom = 12 }: Props) {
    const ref = useRef<HTMLDivElement>(null);
    const mapRef = useRef<L.Map | null>(null);
    const layerRef = useRef<L.LayerGroup | null>(null);

    useEffect(() => {
        if (!ref.current || mapRef.current) return;
        const map = L.map(ref.current, { scrollWheelZoom: true }).setView(center, zoom);
        L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
            attribution: '&copy; OpenStreetMap contributors',
            maxZoom: 19,
        }).addTo(map);
        layerRef.current = L.layerGroup().addTo(map);
        mapRef.current = map;
        setTimeout(() => map.invalidateSize(), 100);
        return () => {
            map.remove();
            mapRef.current = null;
            layerRef.current = null;
        };
    }, [center, zoom]);

    useEffect(() => {
        const map = mapRef.current;
        const layer = layerRef.current;
        if (!map || !layer) return;
        layer.clearLayers();
        const valid = points.filter((p) => Number.isFinite(Number(p.lat)) && Number.isFinite(Number(p.lng)));
        const areaLayers: L.Layer[] = [];
        areas.filter((area) => Number.isFinite(Number(area.lat)) && Number.isFinite(Number(area.lng)) && Number(area.radius_meters) > 0).forEach((area) => {
            const circle = L.circle([Number(area.lat), Number(area.lng)], {
                radius: Number(area.radius_meters),
                color: '#2563eb',
                weight: 2,
                fillOpacity: 0.08,
            }).bindPopup(`<strong>${area.code ? `${area.code} — ` : ''}${area.name}</strong><br/><span>Radius: ${Number(area.radius_meters).toLocaleString('id-ID')} m</span>`).addTo(layer);
            areaLayers.push(circle);
        });
        valid.forEach((point) => {
            L.marker([Number(point.lat), Number(point.lng)], { icon: icon(point.type) })
                .bindPopup(`<strong>${point.title}</strong>${point.description ? `<br/><span>${point.description}</span>` : ''}`)
                .addTo(layer);
        });
        if (valid.length > 0) {
            map.fitBounds(L.latLngBounds(valid.map((p) => [Number(p.lat), Number(p.lng)] as [number, number])), { padding: [30, 30], maxZoom: 15 });
        }
        if (valid.length === 0 && areaLayers.length > 0) {
            const bounds = L.featureGroup(areaLayers).getBounds();
            if (bounds.isValid()) map.fitBounds(bounds, { padding: [30, 30], maxZoom: 14 });
        }
    }, [points, areas]);

    return <div ref={ref} style={{ height }} className="w-full overflow-hidden rounded-xl" />;
}
