import { useEffect, useMemo, useRef, useState } from 'react';
import type { AmapConfig, HeatmapMetric, HeatmapPoint } from './types';

type Props = {
  config: AmapConfig;
  points: HeatmapPoint[];
  max: number;
  metric: HeatmapMetric;
  focusQuery: string;
  onMapClick: (longitude: number, latitude: number) => void;
};

type AmapInstance = {
  Map: new (container: HTMLElement, options: Record<string, unknown>) => any;
  HeatMap: new (map: any, options: Record<string, unknown>) => any;
  ToolBar: new (options?: Record<string, unknown>) => any;
  Scale: new (options?: Record<string, unknown>) => any;
  Bounds: new (southWest: [number, number], northEast: [number, number]) => any;
};

declare global {
  interface Window {
    _AMapSecurityConfig?: { securityJsCode: string };
  }
}

function getBounds(points: HeatmapPoint[]) {
  if (points.length === 0) return null;
  let minLng = points[0].lng;
  let maxLng = points[0].lng;
  let minLat = points[0].lat;
  let maxLat = points[0].lat;
  for (let index = 1; index < points.length; index += 1) {
    const point = points[index];
    minLng = Math.min(minLng, point.lng);
    maxLng = Math.max(maxLng, point.lng);
    minLat = Math.min(minLat, point.lat);
    maxLat = Math.max(maxLat, point.lat);
  }
  return { minLng, maxLng, minLat, maxLat };
}

export default function AmapHeatmapCanvas({ config, points, max, metric, focusQuery, onMapClick }: Props) {
  const containerRef = useRef<HTMLDivElement>(null);
  const mapRef = useRef<any>(null);
  const heatmapRef = useRef<any>(null);
  const amapRef = useRef<AmapInstance | null>(null);
  const clickHandlerRef = useRef(onMapClick);
  const [status, setStatus] = useState<'loading' | 'ready' | 'error'>('loading');
  const intensity = useMemo(() => {
    const transform = metric === 'locations'
      ? (value: number) => Math.log1p(value)
      : (value: number) => Math.sqrt(value);
    return {
      points: points.map((point) => ({ ...point, count: transform(point.count) })),
      max: transform(Math.max(1, max)),
    };
  }, [max, metric, points]);

  useEffect(() => {
    clickHandlerRef.current = onMapClick;
  }, [onMapClick]);

  useEffect(() => {
    let cancelled = false;
    const container = containerRef.current;
    if (!container) return undefined;

    async function initialize() {
      try {
        window._AMapSecurityConfig = { securityJsCode: config.securityCode };
        const loaderModule = await import('@amap/amap-jsapi-loader');
        const AMap = await loaderModule.default.load({
          key: config.key,
          version: '2.0',
          plugins: ['AMap.HeatMap', 'AMap.ToolBar', 'AMap.Scale'],
        }) as unknown as AmapInstance;
        if (cancelled || !container) return;

        const map = new AMap.Map(container, {
          viewMode: '2D',
          zoom: 5,
          center: [105.4, 34.4],
          mapStyle: 'amap://styles/whitesmoke',
          resizeEnable: true,
          showLabel: true,
        });
        map.addControl(new AMap.ToolBar({ position: { right: '20px', bottom: '76px' } }));
        map.addControl(new AMap.Scale({ position: { right: '18px', bottom: '24px' } }));
        const heatmap = new AMap.HeatMap(map, {
          radius: 25,
          opacity: [0.12, 0.82],
          gradient: {
            0.1: '#2563eb',
            0.3: '#0891b2',
            0.5: '#16a34a',
            0.68: '#eab308',
            0.84: '#f97316',
            1: '#dc2626',
          },
        });
        map.on('click', (event: any) => {
          clickHandlerRef.current(event.lnglat.getLng(), event.lnglat.getLat());
        });
        mapRef.current = map;
        heatmapRef.current = heatmap;
        amapRef.current = AMap;
        setStatus('ready');
      } catch (error) {
        console.error('AMap initialization failed', error);
        if (!cancelled) setStatus('error');
      }
    }

    initialize();
    return () => {
      cancelled = true;
      heatmapRef.current?.setMap?.(null);
      mapRef.current?.destroy?.();
      heatmapRef.current = null;
      mapRef.current = null;
      amapRef.current = null;
    };
  }, [config.key, config.securityCode]);

  useEffect(() => {
    if (status !== 'ready' || !heatmapRef.current) return;
    heatmapRef.current.setDataSet({ data: intensity.points, max: intensity.max });

    if (!focusQuery || points.length === 0 || !mapRef.current || !amapRef.current) return;
    const bounds = getBounds(points);
    if (!bounds) return;
    if (points.length === 1) {
      mapRef.current.setZoomAndCenter(12, [points[0].lng, points[0].lat]);
      return;
    }
    mapRef.current.setBounds(new amapRef.current.Bounds(
      [bounds.minLng, bounds.minLat],
      [bounds.maxLng, bounds.maxLat],
    ), false, [80, 80, 80, 80]);
  }, [focusQuery, intensity, points, status]);

  return (
    <div className="absolute inset-0 bg-[#eef3f7]">
      <div ref={containerRef} className="h-full w-full" aria-label="车辆运营热力图地图" />
      {status === 'loading' ? (
        <div className="absolute inset-0 grid place-items-center bg-white/76 text-sm font-medium text-slate-500 backdrop-blur-[2px]">
          <span className="flex items-center gap-2.5"><i className="h-4 w-4 animate-spin rounded-full border-2 border-blue-600 border-t-transparent" />正在加载高德地图</span>
        </div>
      ) : null}
      {status === 'error' ? (
        <div className="absolute inset-0 grid place-items-center bg-slate-50 text-center">
          <div><p className="text-sm font-semibold text-slate-700">地图加载失败</p><p className="mt-1 text-xs text-slate-400">请检查高德 Key、域名白名单与网络连接</p></div>
        </div>
      ) : null}
    </div>
  );
}
