import type { WeatherQueryPoint, WeatherPoint, WeatherSnapshot } from '../model/types';

const MARINE_BASE = 'https://marine-api.open-meteo.com/v1/marine';
const WEATHER_BASE = 'https://api.open-meteo.com/v1/forecast';

const MARINE_PARAMS = 'current=wave_height,wave_direction,wave_period,swell_wave_height,swell_wave_direction,sea_surface_temperature';
const WEATHER_PARAMS = 'current=wind_speed_10m,wind_direction_10m,wind_gusts_10m,temperature_2m,weather_code';

const TIMEOUT_MS = 10_000;

/* Open-Meteo 다중 좌표 응답 타입 */
interface MarineCurrentItem {
  wave_height?: number;
  wave_direction?: number;
  wave_period?: number;
  swell_wave_height?: number;
  swell_wave_direction?: number;
  sea_surface_temperature?: number;
}

interface WeatherCurrentItem {
  wind_speed_10m?: number;
  wind_direction_10m?: number;
  wind_gusts_10m?: number;
  temperature_2m?: number;
  weather_code?: number;
}

/* 단일 좌표 응답 */
interface SingleMarineResponse {
  current?: MarineCurrentItem;
}

/* 다중 좌표 응답 — 배열 */
type MarineResponse = SingleMarineResponse | SingleMarineResponse[];

interface SingleWeatherResponse {
  current?: WeatherCurrentItem;
}

type WeatherResponse = SingleWeatherResponse | SingleWeatherResponse[];

function buildMultiCoordParams(points: WeatherQueryPoint[]): string {
  const lats = points.map((p) => p.lat.toFixed(2)).join(',');
  const lons = points.map((p) => p.lon.toFixed(2)).join(',');
  return `latitude=${lats}&longitude=${lons}`;
}

function n(v: number | undefined): number | null {
  return v != null && Number.isFinite(v) ? v : null;
}

/**
 * Open-Meteo Marine + Weather API를 병렬 호출하여 기상 스냅샷 반환.
 * 좌표 배열 기반이므로 수역 centroid 외에도 임의 좌표에 활용 가능.
 */
export async function fetchWeatherForPoints(
  points: WeatherQueryPoint[],
): Promise<WeatherSnapshot> {
  if (points.length === 0) {
    return { points: [], fetchedAt: Date.now() };
  }

  const coords = buildMultiCoordParams(points);
  const ac = new AbortController();
  const timer = setTimeout(() => ac.abort(), TIMEOUT_MS);

  try {
    const [marineRaw, weatherRaw] = await Promise.all([
      fetch(`${MARINE_BASE}?${coords}&${MARINE_PARAMS}`, { signal: ac.signal })
        .then((r) => r.json() as Promise<MarineResponse>),
      fetch(`${WEATHER_BASE}?${coords}&${WEATHER_PARAMS}`, { signal: ac.signal })
        .then((r) => r.json() as Promise<WeatherResponse>),
    ]);

    // 단일 좌표면 배열이 아닌 단일 객체가 반환됨 → 통일
    const marines: SingleMarineResponse[] = Array.isArray(marineRaw) ? marineRaw : [marineRaw];
    const weathers: SingleWeatherResponse[] = Array.isArray(weatherRaw) ? weatherRaw : [weatherRaw];

    const result: WeatherPoint[] = points.map((pt, i) => {
      const mc = marines[i]?.current;
      const wc = weathers[i]?.current;
      return {
        label: pt.label,
        color: pt.color,
        lat: pt.lat,
        lon: pt.lon,
        zoneId: pt.zoneId,
        waveHeight: n(mc?.wave_height),
        waveDirection: n(mc?.wave_direction),
        wavePeriod: n(mc?.wave_period),
        swellHeight: n(mc?.swell_wave_height),
        swellDirection: n(mc?.swell_wave_direction),
        seaSurfaceTemp: n(mc?.sea_surface_temperature),
        windSpeed: n(wc?.wind_speed_10m),
        windDirection: n(wc?.wind_direction_10m),
        windGusts: n(wc?.wind_gusts_10m),
        temperature: n(wc?.temperature_2m),
        weatherCode: n(wc?.weather_code),
      };
    });

    return { points: result, fetchedAt: Date.now() };
  } finally {
    clearTimeout(timer);
  }
}
