import { useEffect, useRef, useState } from 'react';
import { formatSensorMetricValue } from '@/lib/sensor-metrics';

type SensorMapPoint = {
    id: number;
    display_name: string;
    sensor_type_name: string | null;
    latitude: number;
    longitude: number;
    image_url?: string | null;
    latest_data?: Record<string, unknown>;
    latest_received_at?: string | null;
};

type GoogleMapsWindow = Window & {
    google?: {
        maps?: {
            InfoWindow: new (options?: { content?: string | Node }) => {
                close: () => void;
                setContent: (content: string | Node) => void;
                open: (options: { anchor?: unknown; map?: unknown }) => void;
            };
            LatLngBounds: new () => {
                extend: (position: { lat: number; lng: number }) => void;
            };
            Map: new (
                element: HTMLElement,
                options: {
                    center: { lat: number; lng: number };
                    zoom: number;
                    mapTypeControl?: boolean;
                    streetViewControl?: boolean;
                    fullscreenControl?: boolean;
                },
            ) => {
                fitBounds: (bounds: unknown, padding?: number) => void;
            };
            Marker: new (options: {
                map: unknown;
                position: { lat: number; lng: number };
                title: string;
                label?: { text: string; color: string; fontWeight: string };
            }) => {
                addListener: (eventName: string, callback: () => void) => void;
            };
        };
    };
};

const GOOGLE_MAPS_SCRIPT_ID = 'google-maps-javascript-api';
const EAST_ANGLIA_CENTER = { lat: 52.35, lng: 1.15 };
const EAST_ANGLIA_BOUNDS = [
    { lat: 51.85, lng: 0.05 },
    { lat: 53.05, lng: 1.8 },
] as const;
let googleMapsLoader: Promise<void> | null = null;

function loadGoogleMapsApi(apiKey: string): Promise<void> {
    if ((window as GoogleMapsWindow).google?.maps) {
        return Promise.resolve();
    }

    if (googleMapsLoader) {
        return googleMapsLoader;
    }

    googleMapsLoader = new Promise((resolve, reject) => {
        const existingScript = document.getElementById(GOOGLE_MAPS_SCRIPT_ID) as
            | HTMLScriptElement
            | null;

        if (existingScript) {
            existingScript.addEventListener('load', () => resolve(), { once: true });
            existingScript.addEventListener(
                'error',
                () => reject(new Error('Google Maps failed to load.')),
                { once: true },
            );

            return;
        }

        const script = document.createElement('script');
        script.id = GOOGLE_MAPS_SCRIPT_ID;
        script.async = true;
        script.defer = true;
        script.src = `https://maps.googleapis.com/maps/api/js?key=${encodeURIComponent(apiKey)}&v=weekly`;
        script.onload = () => resolve();
        script.onerror = () => reject(new Error('Google Maps failed to load.'));
        document.head.append(script);
    });

    return googleMapsLoader;
}

export default function SensorMap({ sensors }: { sensors: SensorMapPoint[] }) {
    const containerRef = useRef<HTMLDivElement | null>(null);
    const [loadError, setLoadError] = useState<string | null>(null);
    const apiKey = import.meta.env.VITE_GOOGLE_MAPS_API_KEY;

    useEffect(() => {
        const container = containerRef.current;

        if (!container || sensors.length === 0) {
            return;
        }

        if (!apiKey) {
            setLoadError('Set VITE_GOOGLE_MAPS_API_KEY to display the Google map.');

            return;
        }

        setLoadError(null);

        let cancelled = false;

        loadGoogleMapsApi(apiKey)
            .then(() => {
                if (cancelled || !containerRef.current) {
                    return;
                }

                const googleMaps = (window as GoogleMapsWindow).google?.maps;

                if (!googleMaps) {
                    setLoadError('Google Maps loaded without the expected API.');

                    return;
                }

                const map = new googleMaps.Map(containerRef.current, {
                    center: EAST_ANGLIA_CENTER,
                    zoom: 8,
                    mapTypeControl: false,
                    streetViewControl: false,
                    fullscreenControl: true,
                });

                const bounds = new googleMaps.LatLngBounds();
                const infoWindow = new googleMaps.InfoWindow();

                EAST_ANGLIA_BOUNDS.forEach((position) => {
                    bounds.extend(position);
                });

                sensors.forEach((sensor, index) => {
                    const position = {
                        lat: sensor.latitude,
                        lng: sensor.longitude,
                    };

                    bounds.extend(position);

                    const marker = new googleMaps.Marker({
                        map,
                        position,
                        title: sensor.display_name,
                        label: {
                            text: String(index + 1),
                            color: '#ffffff',
                            fontWeight: '700',
                        },
                    });

                    marker.addListener('click', () => {
                        const content = document.createElement('div');
                        const title = document.createElement('strong');
                        title.textContent = sensor.display_name;
                        title.style.color = '#000000';

                        const subtitle = document.createElement('div');
                        subtitle.textContent = sensor.sensor_type_name ?? 'Sensor';
                        subtitle.style.color = '#000000';

                        const meta = document.createElement('div');
                        meta.textContent = `Lat ${sensor.latitude.toFixed(4)}, Lng ${sensor.longitude.toFixed(4)}`;
                        meta.style.fontSize = '12px';
                        meta.style.color = '#000000';
                        meta.style.marginTop = '4px';

                        content.style.minWidth = '140px';
                        content.style.color = '#000000';

                        if (sensor.image_url) {
                            const image = document.createElement('img');
                            image.src = sensor.image_url;
                            image.alt = sensor.display_name;
                            image.style.width = '100%';
                            image.style.height = '88px';
                            image.style.objectFit = 'cover';
                            image.style.borderRadius = '10px';
                            image.style.marginTop = '10px';
                            content.append(image);
                        }

                        const stats = Object.entries(sensor.latest_data ?? {}).slice(0, 4);

                        content.append(title, subtitle, meta);

                        if (sensor.latest_received_at) {
                            const updated = document.createElement('div');
                            updated.textContent = `Updated ${sensor.latest_received_at}`;
                            updated.style.fontSize = '12px';
                            updated.style.color = '#000000';
                            updated.style.marginTop = '4px';
                            content.append(updated);
                        }

                        if (stats.length > 0) {
                            const list = document.createElement('div');
                            list.style.marginTop = '10px';
                            list.style.display = 'grid';
                            list.style.gap = '6px';

                            stats.forEach(([key, value]) => {
                                const item = document.createElement('div');
                                item.textContent = `${key.replaceAll('_', ' ')}: ${formatSensorMetricValue(
                                    key,
                                    value,
                                )}`;
                                item.style.fontSize = '12px';
                                item.style.lineHeight = '1.35';
                                item.style.color = '#000000';
                                list.append(item);
                            });

                            content.append(list);
                        }

                        infoWindow.close();
                        infoWindow.setContent(content);
                        infoWindow.open({
                            anchor: marker,
                            map,
                        });
                    });
                });

                map.fitBounds(bounds, 48);
            })
            .catch(() => {
                if (!cancelled) {
                    setLoadError('Google Maps could not be loaded for this page.');
                }
            });

        return () => {
            cancelled = true;
        };
    }, [apiKey, sensors]);

    if (sensors.length === 0) {
        return (
            <div className="flex h-full min-h-72 items-center justify-center rounded-[1.25rem] border border-dashed border-border/80 bg-muted/25 p-6 text-center text-sm text-muted-foreground">
                Add latitude and longitude to a sensor to show it on the dashboard map.
            </div>
        );
    }

    if (loadError) {
        return (
            <div className="flex min-h-72 flex-col items-center justify-center gap-2 rounded-[1.25rem] border border-dashed border-border/80 bg-muted/25 p-6 text-center">
                <p className="text-sm font-medium text-foreground">Google Maps unavailable</p>
                <p className="max-w-md text-sm text-muted-foreground">{loadError}</p>
            </div>
        );
    }

    return (
        <div className="overflow-hidden rounded-[1.25rem] border border-border/70 bg-muted/20">
            <div ref={containerRef} className="h-[24rem] w-full md:h-[30rem]" />
        </div>
    );
}
