import { useQuery } from '@tanstack/react-query';

// ============================================================
// Open-Meteo API Types
// ============================================================

interface GeocodingResponse {
  results?: Array<{
    latitude: number;
    longitude: number;
    name: string;
    country: string;
  }>;
}

interface WeatherResponse {
  current: {
    temperature_2m: number;
    weather_code: number;
    is_day: number;
  };
  daily: {
    time: string[];
    weather_code: number[];
    temperature_2m_max: number[];
    temperature_2m_min: number[];
  };
}

// ============================================================
// Public Types
// ============================================================

export interface ForecastDay {
  date: string; // ISO yyyy-mm-dd
  weatherCode: number;
  tempMax: number;
  tempMin: number;
  icon: string;
  label: string;
}

export interface WeatherData {
  temperature: number;
  weatherCode: number;
  isDay: boolean;
  cityName: string;
  icon: string;
  label: string;
  forecast: ForecastDay[];
}

// ============================================================
// WMO Weather Code Mapping (deutsch)
// ============================================================

export function getWeatherInfo(
  code: number,
  isDay: boolean,
): { icon: string; label: string } {
  if (code === 0)
    return { icon: isDay ? '\u2600\uFE0F' : '\uD83C\uDF19', label: 'Klar' };
  if (code <= 3)
    return {
      icon: isDay ? '\u26C5' : '\uD83C\uDF19',
      label: 'Teilweise bew\u00F6lkt',
    };
  if (code <= 49)
    return { icon: '\u2601\uFE0F', label: 'Bew\u00F6lkt' };
  if (code <= 59)
    return { icon: '\uD83C\uDF27\uFE0F', label: 'Nieselregen' };
  if (code <= 69)
    return { icon: '\uD83C\uDF27\uFE0F', label: 'Regen' };
  if (code <= 79)
    return { icon: '\uD83C\uDF28\uFE0F', label: 'Schnee' };
  if (code <= 84)
    return { icon: '\uD83C\uDF27\uFE0F', label: 'Regenschauer' };
  if (code <= 94)
    return { icon: '\uD83C\uDF28\uFE0F', label: 'Schneeschauer' };
  if (code <= 99)
    return { icon: '\u26C8\uFE0F', label: 'Gewitter' };
  return { icon: '\u2601\uFE0F', label: 'Bew\u00F6lkt' };
}

// ============================================================
// Hook
// ============================================================

export function useWeather(city: string | null | undefined) {
  // Schritt 1: City -> Koordinaten (Geocoding)
  const geocoding = useQuery<GeocodingResponse>({
    queryKey: ['geocoding', city],
    queryFn: async () => {
      const url = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(city!)}&count=1&language=de&format=json`;
      const res = await fetch(url);
      if (!res.ok) throw new Error('Geocoding fehlgeschlagen');
      return res.json() as Promise<GeocodingResponse>;
    },
    enabled: !!city && city.trim().length >= 2,
    staleTime: 24 * 60 * 60 * 1000, // 24 Stunden
    retry: 1,
  });

  const geoResult = geocoding.data?.results?.[0];

  // Schritt 2: Koordinaten -> Aktuelles Wetter + 3-Tage-Prognose
  const weather = useQuery<WeatherResponse>({
    queryKey: ['weather', geoResult?.latitude, geoResult?.longitude],
    queryFn: async () => {
      const url =
        `https://api.open-meteo.com/v1/forecast` +
        `?latitude=${geoResult!.latitude}&longitude=${geoResult!.longitude}` +
        `&current=temperature_2m,weather_code,is_day` +
        `&daily=weather_code,temperature_2m_max,temperature_2m_min` +
        `&forecast_days=3&timezone=auto`;
      const res = await fetch(url);
      if (!res.ok) throw new Error('Wetter-Abfrage fehlgeschlagen');
      return res.json() as Promise<WeatherResponse>;
    },
    enabled: !!geoResult,
    staleTime: 15 * 60 * 1000, // 15 Minuten
    retry: 1,
  });

  // Ergebnis zusammenbauen
  const data: WeatherData | undefined =
    weather.data && geoResult
      ? (() => {
          const { temperature_2m, weather_code, is_day } = weather.data.current;
          const info = getWeatherInfo(weather_code, is_day === 1);

          // 3-Tage-Prognose
          const forecast: ForecastDay[] = (weather.data.daily?.time ?? []).map(
            (date, i) => {
              const code = weather.data!.daily.weather_code[i] ?? 0;
              const fi = getWeatherInfo(code, true); // Tagessymbole für Prognose
              return {
                date,
                weatherCode: code,
                tempMax: Math.round(weather.data!.daily.temperature_2m_max[i] ?? 0),
                tempMin: Math.round(weather.data!.daily.temperature_2m_min[i] ?? 0),
                icon: fi.icon,
                label: fi.label,
              };
            },
          );

          return {
            temperature: temperature_2m,
            weatherCode: weather_code,
            isDay: is_day === 1,
            cityName: geoResult.name,
            icon: info.icon,
            label: info.label,
            forecast,
          };
        })()
      : undefined;

  return {
    data,
    isLoading: geocoding.isLoading || weather.isLoading,
    isError: geocoding.isError || weather.isError,
  };
}
