'use client';

/* eslint-disable import-x/no-named-as-default-member */
import mapboxgl from 'mapbox-gl';
import * as React from 'react';
import 'mapbox-gl/dist/mapbox-gl.css';
import { MAPBOX_STYLE_DARK, useMapboxStyle } from '@/lib/mapbox-style';

export interface HeatmapPoint {
  district: string;
  avgPriceM2: number;
  totalListings: number;
  medianPrice: string;
}

interface DistrictHeatmapProps {
  data: HeatmapPoint[];
  city: string;
  className?: string;
  onDistrictClick?: (district: string) => void;
}

/** Approximate centroids for major districts. Fallback spreads unknown districts around city center. */
const DISTRICT_COORDS: Record<string, Record<string, [number, number]>> = {
  'Ho Chi Minh': {
    'Quan 1': [106.6985, 10.7756],
    'Quan 2': [106.7518, 10.7870],
    'Quan 3': [106.6870, 10.7830],
    'Quan 4': [106.7040, 10.7580],
    'Quan 5': [106.6600, 10.7540],
    'Quan 6': [106.6350, 10.7480],
    'Quan 7': [106.7220, 10.7340],
    'Quan 8': [106.6280, 10.7380],
    'Quan 9': [106.8260, 10.8480],
    'Quan 10': [106.6680, 10.7720],
    'Quan 11': [106.6500, 10.7620],
    'Quan 12': [106.6420, 10.8670],
    'Binh Thanh': [106.7130, 10.8070],
    'Phu Nhuan': [106.6800, 10.7990],
    'Go Vap': [106.6540, 10.8370],
    'Tan Binh': [106.6530, 10.8010],
    'Tan Phu': [106.6280, 10.7920],
    'Thu Duc': [106.7630, 10.8560],
    'Binh Tan': [106.5920, 10.7650],
    'Nha Be': [106.7300, 10.6940],
    'Can Gio': [106.9530, 10.4110],
    'Hoc Mon': [106.5920, 10.8860],
    'Cu Chi': [106.4930, 10.9730],
    'Binh Chanh': [106.5420, 10.7350],
  },
  'Ha Noi': {
    'Hoan Kiem': [105.8544, 21.0285],
    'Ba Dinh': [105.8193, 21.0340],
    'Dong Da': [105.8304, 21.0168],
    'Hai Ba Trung': [105.8634, 21.0120],
    'Cau Giay': [105.7968, 21.0340],
    'Thanh Xuan': [105.8100, 21.0000],
    'Tay Ho': [105.8180, 21.0720],
    'Long Bien': [105.8890, 21.0450],
    'Nam Tu Liem': [105.7550, 21.0180],
    'Bac Tu Liem': [105.7660, 21.0520],
    'Ha Dong': [105.7530, 20.9700],
    'Hoang Mai': [105.8620, 20.9800],
  },
  'Da Nang': {
    'Hai Chau': [108.2180, 16.0680],
    'Thanh Khe': [108.1850, 16.0670],
    'Son Tra': [108.2540, 16.1010],
    'Ngu Hanh Son': [108.2530, 16.0190],
    'Lien Chieu': [108.1440, 16.0820],
    'Cam Le': [108.2080, 16.0230],
  },
};

const CITY_CENTER: Record<string, [number, number]> = {
  'Ho Chi Minh': [106.6600, 10.7900],
  'Ha Noi': [105.8342, 21.0278],
  'Da Nang': [108.2022, 16.0544],
};

function getCoord(city: string, district: string, index: number): [number, number] {
  const cityCoords = DISTRICT_COORDS[city];
  if (cityCoords?.[district]) return cityCoords[district];
  const center = CITY_CENTER[city] ?? [106.66, 10.79];
  // Spread unknowns in a ring around center
  const angle = (index * 137.5 * Math.PI) / 180;
  const r = 0.015 + index * 0.003;
  return [center[0] + Math.cos(angle) * r, center[1] + Math.sin(angle) * r];
}

function priceColor(ratio: number): string {
  // 0 = green/cheap, 1 = red/expensive
  const h = 120 - ratio * 120; // 120 (green) -> 0 (red)
  return `hsl(${h}, 75%, 50%)`;
}

export function DistrictHeatmap({ data, city, className, onDistrictClick }: DistrictHeatmapProps) {
  const mapContainerRef = React.useRef<HTMLDivElement>(null);
  const mapRef = React.useRef<mapboxgl.Map | null>(null);
  const markersRef = React.useRef<mapboxgl.Marker[]>([]);
  const themeStyle = useMapboxStyle();
  // Heatmap uses the lighter "light-v11" backdrop for better marker contrast in
  // light mode; in dark mode, fall back to the shared dark style.
  const mapStyle =
    themeStyle === MAPBOX_STYLE_DARK ? MAPBOX_STYLE_DARK : 'mapbox://styles/mapbox/light-v11';

  const maxPrice = React.useMemo(() => Math.max(...data.map((d) => d.avgPriceM2), 1), [data]);

  React.useEffect(() => {
    if (!mapContainerRef.current) return;

    const token = process.env['NEXT_PUBLIC_MAPBOX_TOKEN'];
    if (!token) return;

    mapboxgl.accessToken = token;

    const center = CITY_CENTER[city] ?? [106.66, 10.79];
    const map = new mapboxgl.Map({
      container: mapContainerRef.current,
      style: mapStyle,
      center: center as [number, number],
      zoom: 11,
      attributionControl: false,
    });

    map.addControl(new mapboxgl.NavigationControl(), 'top-right');
    mapRef.current = map;

    return () => {
      map.remove();
      mapRef.current = null;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [city]);

  // Sync style changes with theme. The heatmap "layer" is implemented as DOM
  // markers (re-added by the effect below when data changes), so we also need
  // to re-add markers after the style finishes loading in case the style swap
  // raced with a data update.
  React.useEffect(() => {
    const map = mapRef.current;
    if (!map) return;
    map.setStyle(mapStyle);
  }, [mapStyle]);

  // Update markers
  React.useEffect(() => {
    const map = mapRef.current;
    if (!map) return;

    markersRef.current.forEach((m) => m.remove());
    markersRef.current = [];

    if (data.length === 0) return;

    const bounds = new mapboxgl.LngLatBounds();

    data.forEach((point, i) => {
      const coord = getCoord(city, point.district, i);
      const ratio = point.avgPriceM2 / maxPrice;
      const size = 36 + ratio * 28; // 36px to 64px

      // Mapbox writes `transform: translate(...)` on the marker element;
      // hover-scaling the outer element clobbers it. Scale an inner div
      // instead.
      const el = document.createElement('button');
      el.style.cssText = `width: ${size}px; height: ${size}px; padding: 0; border: none; background: transparent; cursor: pointer;`;
      const inner = document.createElement('div');
      inner.style.cssText = `
        width: 100%; height: 100%;
        border-radius: 50%; border: 2px solid white;
        background: ${priceColor(ratio)};
        opacity: 0.8;
        display: flex; align-items: center; justify-content: center;
        font-size: 10px; font-weight: 700; color: white;
        text-shadow: 0 1px 2px rgba(0,0,0,0.5);
        box-shadow: 0 2px 6px rgba(0,0,0,0.3);
        transition: transform 0.15s, opacity 0.15s;
        transform: scale(1);
        padding: 2px;
        line-height: 1.1;
        text-align: center;
        pointer-events: none;
      `;
      inner.textContent = point.district.replace(/^Quan\s*/i, 'Q.').replace(/^Huyen\s*/i, 'H.');
      el.appendChild(inner);
      el.addEventListener('mouseenter', () => { inner.style.opacity = '1'; inner.style.transform = 'scale(1.15)'; });
      el.addEventListener('mouseleave', () => { inner.style.opacity = '0.8'; inner.style.transform = 'scale(1)'; });
      el.addEventListener('click', (e) => {
        e.stopPropagation();
        onDistrictClick?.(point.district);
      });

      const priceLabel = point.avgPriceM2 >= 1_000_000
        ? `${(point.avgPriceM2 / 1_000_000).toFixed(1)} tr/m²`
        : `${Math.round(point.avgPriceM2 / 1000)}k/m²`;

      const popup = new mapboxgl.Popup({ offset: 15, closeButton: false })
        .setHTML(`
          <div style="font-family:system-ui,sans-serif;background:hsl(var(--card));color:hsl(var(--card-foreground));padding:8px;border-radius:6px;">
            <div style="font-weight:700;font-size:13px;margin-bottom:4px;">${point.district}</div>
            <div style="font-size:12px;color:hsl(var(--primary));font-weight:600;">${priceLabel}</div>
            <div style="font-size:11px;color:hsl(var(--muted-foreground));margin-top:2px;">${point.totalListings} tin đăng</div>
          </div>
        `);

      const marker = new mapboxgl.Marker({ element: el, anchor: 'center' })
        .setLngLat(coord)
        .setPopup(popup)
        .addTo(map);

      markersRef.current.push(marker);
      bounds.extend(coord);
    });

    if (data.length > 1) {
      map.fitBounds(bounds, { padding: 50, maxZoom: 13 });
    }
  }, [data, city, maxPrice, onDistrictClick]);

  const hasToken = typeof process !== 'undefined' && process.env['NEXT_PUBLIC_MAPBOX_TOKEN'];

  return (
    <div className={`relative overflow-hidden rounded-lg ${className || 'h-[400px]'}`}>
      <div ref={mapContainerRef} className="h-full w-full" />
      {!hasToken && (
        <div className="absolute inset-0 flex items-center justify-center bg-gradient-to-b from-blue-50 to-green-50">
          <div className="text-center">
            <svg className="mx-auto mb-2 h-10 w-10 text-muted-foreground" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4m0 0L9 7" />
            </svg>
            <p className="text-sm text-muted-foreground">
              Thiết lập NEXT_PUBLIC_MAPBOX_TOKEN để hiển thị bản đồ nhiệt
            </p>
          </div>
        </div>
      )}
      {/* Legend */}
      <div className="absolute bottom-3 left-3 rounded bg-white/90 px-3 py-2 text-xs shadow">
        <div className="mb-1 font-medium">Giá trung bình/m²</div>
        <div className="flex items-center gap-1">
          <div className="h-3 w-3 rounded-full" style={{ background: priceColor(0) }} />
          <span>Thấp</span>
          <div className="mx-1 h-2 w-16 rounded" style={{ background: 'linear-gradient(to right, hsl(120,75%,50%), hsl(60,75%,50%), hsl(0,75%,50%))' }} />
          <div className="h-3 w-3 rounded-full" style={{ background: priceColor(1) }} />
          <span>Cao</span>
        </div>
      </div>
    </div>
  );
}
