import { useState, useEffect } from "react";
import { Cloud, Sun, CloudRain, CloudSnow, CloudLightning, CloudDrizzle, Wind, Droplets, Thermometer, MapPin } from "lucide-react";

interface WeatherData {
  temperature: number;
  weatherCode: number;
  windSpeed: number;
  humidity: number;
  city: string;
}

function getWeatherIcon(code: number) {
  if (code === 0 || code === 1) return <Sun className="w-8 h-8 text-yellow-400" />;
  if (code === 2 || code === 3) return <Cloud className="w-8 h-8 text-gray-400" />;
  if (code >= 51 && code <= 57) return <CloudDrizzle className="w-8 h-8 text-blue-300" />;
  if (code >= 61 && code <= 67) return <CloudRain className="w-8 h-8 text-blue-400" />;
  if (code >= 71 && code <= 77) return <CloudSnow className="w-8 h-8 text-white" />;
  if (code >= 80 && code <= 82) return <CloudRain className="w-8 h-8 text-blue-500" />;
  if (code >= 95) return <CloudLightning className="w-8 h-8 text-yellow-500" />;
  return <Cloud className="w-8 h-8 text-gray-400" />;
}

function getWeatherText(code: number): string {
  if (code === 0) return "Klar";
  if (code === 1) return "Überwiegend klar";
  if (code === 2) return "Teilweise bewölkt";
  if (code === 3) return "Bewölkt";
  if (code >= 51 && code <= 57) return "Nieselregen";
  if (code >= 61 && code <= 65) return "Regen";
  if (code === 66 || code === 67) return "Gefrierender Regen";
  if (code >= 71 && code <= 75) return "Schneefall";
  if (code === 77) return "Schneegriesel";
  if (code >= 80 && code <= 82) return "Regenschauer";
  if (code === 85 || code === 86) return "Schneeschauer";
  if (code >= 95) return "Gewitter";
  return "Unbekannt";
}

async function reverseGeocode(lat: number, lon: number): Promise<string> {
  try {
    const res = await fetch(`https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lon}&format=json&zoom=10&accept-language=de`);
    const data = await res.json();
    return data.address?.city || data.address?.town || data.address?.village || data.address?.municipality || "Unbekannt";
  } catch {
    return "Unbekannt";
  }
}

export function WeatherWidget() {
  const [weather, setWeather] = useState<WeatherData | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(false);

  useEffect(() => {
    const defaultLat = 46.55;
    const defaultLon = 14.55;
    const defaultCity = "Klagenfurt";

    async function fetchWeather(lat: number, lon: number, city: string) {
      try {
        const res = await fetch(
          `https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}&current=temperature_2m,weather_code,wind_speed_10m,relative_humidity_2m&timezone=auto`
        );
        const data = await res.json();
        setWeather({
          temperature: Math.round(data.current.temperature_2m),
          weatherCode: data.current.weather_code,
          windSpeed: Math.round(data.current.wind_speed_10m),
          humidity: data.current.relative_humidity_2m,
          city,
        });
      } catch {
        setError(true);
      } finally {
        setLoading(false);
      }
    }

    async function getLocationByIP() {
      try {
        const res = await fetch("https://ipapi.co/json/");
        const data = await res.json();
        if (data.latitude && data.longitude) {
          const city = data.city || await reverseGeocode(data.latitude, data.longitude);
          fetchWeather(data.latitude, data.longitude, city);
        } else {
          fetchWeather(defaultLat, defaultLon, defaultCity);
        }
      } catch {
        fetchWeather(defaultLat, defaultLon, defaultCity);
      }
    }

    getLocationByIP();
  }, []);

  if (loading) {
    return (
      <div className="bg-card rounded-lg border border-card-border p-4 h-full" data-testid="widget-weather-loading">
        <div className="flex items-center gap-2 mb-3">
          <Thermometer className="w-4 h-4 text-primary" />
          <h3 className="font-bold text-card-foreground text-sm">Wetter</h3>
        </div>
        <div className="h-16 bg-muted animate-pulse rounded" />
      </div>
    );
  }

  if (error || !weather) return null;

  return (
    <div className="bg-card rounded-lg border border-card-border px-3 py-2" data-testid="widget-weather">
      <div className="flex items-center gap-3">
        <div className="flex-shrink-0">{getWeatherIcon(weather.weatherCode)}</div>
        <div className="flex-1 min-w-0">
          <div className="flex items-baseline gap-1.5">
            <span className="text-lg font-bold text-card-foreground">{weather.temperature}°C</span>
            <span className="text-[10px] text-muted-foreground">{getWeatherText(weather.weatherCode)}</span>
          </div>
          <div className="flex items-center gap-3 text-[10px] text-muted-foreground">
            <span className="flex items-center gap-0.5"><MapPin className="w-2.5 h-2.5" />{weather.city}</span>
            <span className="flex items-center gap-0.5"><Wind className="w-2.5 h-2.5" />{weather.windSpeed} km/h</span>
            <span className="flex items-center gap-0.5"><Droplets className="w-2.5 h-2.5" />{weather.humidity}%</span>
          </div>
        </div>
      </div>
    </div>
  );
}

export function SidebarWeatherWidget() {
  const [weather, setWeather] = useState<WeatherData | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const defaultLat = 46.55;
    const defaultLon = 14.55;
    const defaultCity = "Klagenfurt";

    async function fetchWeather(lat: number, lon: number, city: string) {
      try {
        const res = await fetch(
          `https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}&current=temperature_2m,weather_code,wind_speed_10m,relative_humidity_2m&daily=temperature_2m_max,temperature_2m_min,weather_code&timezone=auto&forecast_days=3`
        );
        const data = await res.json();
        setWeather({
          temperature: Math.round(data.current.temperature_2m),
          weatherCode: data.current.weather_code,
          windSpeed: Math.round(data.current.wind_speed_10m),
          humidity: data.current.relative_humidity_2m,
          city,
        });
        setForecast(data.daily ? data.daily.time.slice(1, 3).map((d: string, i: number) => ({
          day: new Date(d).toLocaleDateString("de-DE", { weekday: "short" }),
          high: Math.round(data.daily.temperature_2m_max[i + 1]),
          low: Math.round(data.daily.temperature_2m_min[i + 1]),
          code: data.daily.weather_code[i + 1],
        })) : []);
      } catch {
      } finally {
        setLoading(false);
      }
    }

    async function getLocationByIP() {
      try {
        const res = await fetch("https://ipapi.co/json/");
        const ipData = await res.json();
        if (ipData.latitude && ipData.longitude) {
          fetchWeather(ipData.latitude, ipData.longitude, ipData.city || "Unbekannt");
        } else {
          fetchWeather(defaultLat, defaultLon, defaultCity);
        }
      } catch {
        fetchWeather(defaultLat, defaultLon, defaultCity);
      }
    }

    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(
        async (pos) => {
          try {
            const res = await fetch(`https://nominatim.openstreetmap.org/reverse?lat=${pos.coords.latitude}&lon=${pos.coords.longitude}&format=json&accept-language=de`);
            const geo = await res.json();
            const city = geo.address?.city || geo.address?.town || geo.address?.village || "Unbekannt";
            fetchWeather(pos.coords.latitude, pos.coords.longitude, city);
          } catch {
            fetchWeather(pos.coords.latitude, pos.coords.longitude, "Unbekannt");
          }
        },
        () => { getLocationByIP(); },
        { timeout: 5000 }
      );
    } else {
      getLocationByIP();
    }
  }, []);

  const [forecast, setForecast] = useState<{ day: string; high: number; low: number; code: number }[]>([]);

  if (loading) {
    return (
      <div className="bg-card rounded-lg border border-card-border p-4 aspect-square flex items-center justify-center" data-testid="sidebar-weather-loading">
        <div className="w-full h-full bg-muted animate-pulse rounded" />
      </div>
    );
  }

  if (!weather) return null;

  return (
    <div className="bg-gradient-to-br from-card to-card/80 rounded-lg border border-card-border p-4 aspect-square flex flex-col justify-between" data-testid="sidebar-weather">
      <div className="flex items-center justify-between">
        <div className="flex items-center gap-1.5">
          <MapPin className="w-3.5 h-3.5 text-primary" />
          <span className="text-xs font-semibold text-card-foreground">{weather.city}</span>
        </div>
        <span className="text-[10px] text-muted-foreground">
          {new Date().toLocaleDateString("de-DE", { weekday: "short", day: "numeric", month: "short" })}
        </span>
      </div>

      <div className="flex items-center justify-center gap-3 flex-1">
        <div className="scale-150">{getWeatherIcon(weather.weatherCode)}</div>
        <div>
          <div className="text-3xl font-bold text-card-foreground leading-none">{weather.temperature}°</div>
          <div className="text-xs text-muted-foreground mt-0.5">{getWeatherText(weather.weatherCode)}</div>
        </div>
      </div>

      <div className="flex items-center justify-between text-[10px] text-muted-foreground border-t border-card-border pt-2 mb-2">
        <span className="flex items-center gap-1"><Wind className="w-3 h-3" />{weather.windSpeed} km/h</span>
        <span className="flex items-center gap-1"><Droplets className="w-3 h-3" />{weather.humidity}%</span>
      </div>

      {forecast.length > 0 && (
        <div className="flex gap-2 border-t border-card-border pt-2">
          {forecast.map((f) => (
            <div key={f.day} className="flex-1 text-center">
              <div className="text-[10px] text-muted-foreground mb-1">{f.day}</div>
              <div className="flex justify-center scale-75">{getWeatherIcon(f.code)}</div>
              <div className="text-[10px] text-card-foreground font-medium">{f.high}°</div>
              <div className="text-[10px] text-muted-foreground">{f.low}°</div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}
