import { useState, useEffect, useRef } from 'react'
import WeatherDashboard from './components/WeatherDashboard'
import { getSunTimes, getMoonPhase, formatTime, formatMoonPhase } from './utils/astro'
import './App.css'

// Grad/Minuten/Sekunden in Dezimalgrad
const dms = (deg, min, sec) => deg + min / 60 + sec / 3600

// Dezimalgrad zurueck nach Grad/Minuten/Sekunden fuer die Anzeige
function formatDms(value) {
  let deg = Math.floor(value)
  let min = Math.floor((value - deg) * 60)
  let sec = Math.round(((value - deg) * 60 - min) * 60)
  if (sec === 60) { sec = 0; min += 1 }   // Rundungsuebertrag
  if (min === 60) { min = 0; deg += 1 }
  return `${deg}° ${min}′ ${sec}″`
}

// Standort der Wetterstation — Basis fuer Header-Anzeige und Astro-Berechnung
const STATION = {
  lat: dms(48, 52, 27),   // noerdliche Breite
  lon: dms(9, 35, 46),    // oestliche Laenge
  elevation: 547,         // Meter ueber NN — nur Anzeige, siehe ZENITH in astro.js
}

// API-Basis-URL: in Dev direkt auf Backend, in Prod ueber Nginx-Proxy
const API_BASE = import.meta.env.DEV ? 'http://localhost:8000' : '/api'

// 24-Stunden-URL fuer "Aktuell"-Anzeige (auch bei laengeren Zeitraeumen gebraucht)
const CURRENT_URL = `${API_BASE}/weather/history?hours=24&limit=5000`

// JSON-Fetch-Helfer: liefert {ok, data} oder wirft bei Netzfehler.
// Per signal kann der Request abgebrochen werden, wenn timeRange wechselt.
async function fetchJson(url, signal) {
  const res = await fetch(url, { signal })
  if (!res.ok) throw new Error(`HTTP ${res.status} bei ${url}`)
  return res.json()
}

// Bestimmt die URLs fuer den gewaehlten Zeitbereich.
// Returns: { weatherUrl, rainUrl, needsCurrent }
function buildUrls(timeRange) {
  // Custom-Range
  if (typeof timeRange === 'object' && timeRange.type === 'custom') {
    const start = encodeURIComponent(timeRange.start)
    const end   = encodeURIComponent(timeRange.end)
    const days  = timeRange.days || 1
    const path = days >= 7 ? 'daily-aggregated-range' : 'hourly-aggregated-range'
    return {
      weatherUrl: `${API_BASE}/weather/${path}?start=${start}&end=${end}`,
      rainUrl:    days < 7 ? `${API_BASE}/weather/daily-aggregated-range?start=${start}&end=${end}` : null,
      needsCurrent: true,
    }
  }

  switch (timeRange) {
    case '24h':
      return {
        weatherUrl:   `${API_BASE}/weather/history?hours=24&limit=5000`,
        rainUrl:      null,
        needsCurrent: false,  // Hauptdaten SIND die aktuellen 24h-Daten
      }
    case '7d':
      return {
        weatherUrl:   `${API_BASE}/weather/daily-with-minmax?days=7`,
        rainUrl:      `${API_BASE}/weather/rain-daily?days=7`,
        needsCurrent: true,
      }
    case '30d':
      return {
        weatherUrl:   `${API_BASE}/weather/daily-with-minmax?days=30`,
        rainUrl:      `${API_BASE}/weather/rain-daily?days=30`,
        needsCurrent: true,
      }
    case '365d':
      return {
        weatherUrl:   `${API_BASE}/weather/daily-aggregated?days=365`,
        rainUrl:      `${API_BASE}/weather/rain-weekly?days=365`,
        needsCurrent: true,
      }
    default:
      return {
        weatherUrl:   `${API_BASE}/weather/history?hours=24`,
        rainUrl:      null,
        needsCurrent: false,
      }
  }
}

function App() {
  const [weatherData, setWeatherData] = useState([])
  const [currentWeatherData, setCurrentWeatherData] = useState([])
  const [rainData, setRainData] = useState([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(null)
  const [lastUpdate, setLastUpdate] = useState(null)
  const [timeRange, setTimeRange] = useState('24h')
  const [showTable, setShowTable] = useState(false)

  // Erster-Lade-Flag: nur beim allerersten Fetch zeigen wir den Spinner.
  // Bei spaeteren Re-Fetches (Auto-Refresh, Time-Range-Wechsel) bleiben die
  // alten Daten sichtbar, bis die neuen da sind — flackert weniger.
  const isInitialLoadRef = useRef(true)

  const handleTimeRangeChange = (range, customParams) => {
    if (range === 'custom' && customParams) {
      const start = new Date(customParams.start)
      const end   = new Date(customParams.end)
      const days  = Math.ceil((end - start) / (1000 * 60 * 60 * 24))
      setTimeRange({ type: 'custom', start: customParams.start, end: customParams.end, days })
    } else {
      setTimeRange(range)
    }
  }

  useEffect(() => {
    // Statische Daten: kein Fetch noetig
    if (window.__WEATHER_DATA__ && timeRange === '24h') {
      setWeatherData(window.__WEATHER_DATA__)
      setCurrentWeatherData(window.__WEATHER_DATA__)
      setRainData([])
      setLastUpdate(new Date())
      setLoading(false)
      return
    }

    const controller = new AbortController()

    const fetchData = async () => {
      if (isInitialLoadRef.current) setLoading(true)

      const { weatherUrl, rainUrl, needsCurrent } = buildUrls(timeRange)

      // Alle drei Requests parallel starten (statt sequentiell wie vorher).
      // allSettled, damit ein Fehler bei rain/current die Hauptdaten nicht blockiert.
      const requests = [
        fetchJson(weatherUrl, controller.signal),                       // [0] weather - Pflicht
        needsCurrent ? fetchJson(CURRENT_URL, controller.signal) : null, // [1] current  - optional
        rainUrl     ? fetchJson(rainUrl, controller.signal)     : null, // [2] rain     - optional
      ]
      const results = await Promise.allSettled(requests.map(p => p ?? Promise.resolve(null)))

      // AbortError ignorieren — passiert, wenn timeRange waehrend des Requests
      // gewechselt hat. Der nachfolgende Effekt-Lauf macht den richtigen Fetch.
      const aborted = results.some(
        r => r.status === 'rejected' && r.reason?.name === 'AbortError'
      )
      if (aborted) return

      // Hauptdaten-Fehler ist fatal; ohne die zeigen wir nichts an.
      if (results[0].status === 'rejected') {
        setError(results[0].reason?.message || 'Unbekannter Fehler')
        setLoading(false)
        isInitialLoadRef.current = false
        return
      }

      const weatherResult = results[0].value
      const currentResult = results[1].status === 'fulfilled' ? results[1].value : null
      const rainResult    = results[2].status === 'fulfilled' ? results[2].value : null

      setError(null)
      setWeatherData(weatherResult)
      // Wenn 24h gewaehlt ist, sind weather und current dieselben Daten
      setCurrentWeatherData(needsCurrent ? (currentResult ?? []) : weatherResult)
      setRainData(rainResult ?? [])
      setLastUpdate(new Date())
      setLoading(false)
      isInitialLoadRef.current = false
    }

    fetchData()

    // Auto-Refresh nur bei 24h, nur wenn keine statischen Daten
    let interval = null
    if (!window.__WEATHER_DATA__ && timeRange === '24h') {
      interval = setInterval(fetchData, 5 * 60 * 1000)
    }

    return () => {
      controller.abort()
      if (interval) clearInterval(interval)
    }
  }, [timeRange])

  if (loading) {
    return (
      <div className="loading-container">
        <div className="loading-spinner"></div>
        <p>Lade Wetterdaten...</p>
      </div>
    )
  }

  if (error) {
    return (
      <div className="error-container">
        <h2>Fehler beim Laden der Daten</h2>
        <p>{error}</p>
      </div>
    )
  }

  // Aktuelle Zeit formatieren
  const now = new Date()
  const dateStr = now.toLocaleDateString('de-DE', {
    weekday: 'long',
    year: 'numeric',
    month: 'long',
    day: 'numeric'
  })
  const timeStr = now.toLocaleTimeString('de-DE', {
    hour: '2-digit',
    minute: '2-digit'
  })

  // Sonnenauf-/untergang fuer heute am Stationsstandort
  const sunTimes = getSunTimes(now, STATION.lat, STATION.lon)
  const sunrise = formatTime(sunTimes.sunrise)
  const sunset  = formatTime(sunTimes.sunset)

  // Mondphase zum aktuellen Zeitpunkt
  const moonPhase = formatMoonPhase(getMoonPhase(now))

  return (
    <div className="app">
      <header className="app-header">
        <h1>Aktuelle Wetterdaten</h1>
        <div className="header-datetime">{dateStr} - {timeStr} Uhr</div>
        <div className="header-spacer"></div>
        <div className="header-coordinates">
          {formatDms(STATION.lat)} N - {formatDms(STATION.lon)} E - {STATION.elevation} m NN
        </div>
        <div className="header-astro">
          Sonnen-Aufgang: {sunrise} - Untergang: {sunset} &nbsp;&nbsp; Mond-Phase: {moonPhase}
        </div>
      </header>

      <main className="app-main">
        <WeatherDashboard
          data={weatherData}
          currentData={currentWeatherData}
          rainData={rainData}
          timeRange={timeRange}
          onTimeRangeChange={handleTimeRangeChange}
          showTable={showTable}
          onToggleTable={() => setShowTable(v => !v)}
        />
      </main>
    </div>
  )
}

export default App
