import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import type { ZonesGeoJson } from '../../entities/zone/api/useZones';
import { ZONE_META, type ZoneId } from '../../entities/zone/model/meta';
import type { WeatherQueryPoint, WeatherSnapshot } from '../../entities/weather/model/types';
import { fetchWeatherForPoints } from '../../entities/weather/api/fetchWeather';
import { computeMultiPolygonCentroid } from '../../entities/weather/lib/weatherUtils';

const POLL_INTERVAL_MS = 5 * 60 * 1000; // 5분

/**
 * zones GeoJSON에서 조회 지점(centroid) 목록 생성.
 * zoneId 속성이 있는 Feature만 사용.
 */
function buildQueryPoints(zones: ZonesGeoJson): WeatherQueryPoint[] {
  const points: WeatherQueryPoint[] = [];

  for (const feature of zones.features) {
    const zoneId = feature.properties?.zoneId as ZoneId | undefined;
    if (!zoneId || !ZONE_META[zoneId]) continue;

    const meta = ZONE_META[zoneId];
    const [lon, lat] = computeMultiPolygonCentroid(
      feature.geometry.coordinates as number[][][][],
    );

    points.push({
      label: `${meta.label} ${meta.name}`,
      color: meta.color,
      lat,
      lon,
      zoneId,
    });
  }

  return points;
}

export interface WeatherPollingResult {
  snapshot: WeatherSnapshot | null;
  isLoading: boolean;
  error: string | null;
  refresh: () => void;
}

/**
 * 수역 기상 데이터를 5분 간격으로 폴링하는 훅.
 * zonesGeoJson이 null이면 대기 (아직 로딩 안 된 경우).
 */
export function useWeatherPolling(
  zonesGeoJson: ZonesGeoJson | null,
): WeatherPollingResult {
  const [snapshot, setSnapshot] = useState<WeatherSnapshot | null>(null);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const abortRef = useRef<AbortController | null>(null);

  const queryPoints = useMemo(() => {
    if (!zonesGeoJson) return null;
    return buildQueryPoints(zonesGeoJson);
  }, [zonesGeoJson]);

  const doFetch = useCallback(async () => {
    if (!queryPoints || queryPoints.length === 0) return;

    abortRef.current?.abort();
    const ac = new AbortController();
    abortRef.current = ac;

    setIsLoading(true);
    setError(null);

    try {
      const result = await fetchWeatherForPoints(queryPoints);
      if (ac.signal.aborted) return;
      setSnapshot(result);
    } catch (e) {
      if (ac.signal.aborted) return;
      setError(e instanceof Error ? e.message : String(e));
    } finally {
      if (!ac.signal.aborted) setIsLoading(false);
    }
  }, [queryPoints]);

  // 마운트 + queryPoints 변경 시 즉시 1회 호출 + 5분 간격 폴링
  useEffect(() => {
    if (!queryPoints || queryPoints.length === 0) return;

    void doFetch();
    const timer = setInterval(() => void doFetch(), POLL_INTERVAL_MS);
    return () => {
      clearInterval(timer);
      abortRef.current?.abort();
    };
  }, [queryPoints, doFetch]);

  return { snapshot, isLoading, error, refresh: doFetch };
}
