import SwiftUI
import WeatherKit
import CoreLocation

struct WetterView: View {
    @State private var location = OneShotLocation()
    @State private var weather: Weather?
    @State private var isLoading = false
    @State private var errorMessage: String?
    @State private var selectedDayIndex = 0

    var body: some View {
        Group {
            if let weather {
                content(weather: weather)
            } else if isLoading {
                ProgressView("Lade Wetter…")
            } else if let errorMessage {
                ContentUnavailableView(
                    "Konnte nicht laden",
                    systemImage: "cloud.slash",
                    description: Text(errorMessage)
                )
            } else if location.error != nil {
                ContentUnavailableView(
                    "Kein Standort",
                    systemImage: "location.slash",
                    description: Text(location.error ?? "")
                )
            } else {
                ProgressView("Hole Standort…")
            }
        }
        .navigationTitle("Gassi-Wetter")
        .navigationBarTitleDisplayMode(.inline)
        .task { location.request() }
        .onChange(of: location.coordinate?.latitude) { _, _ in
            Task { await loadWeather() }
        }
        .refreshable { await loadWeather() }
    }

    private func content(weather: Weather) -> some View {
        let days = Array(weather.dailyForecast.prefix(7))
        let safeIndex = max(0, min(selectedDayIndex, days.count - 1))

        return ScrollView {
            VStack(spacing: 14) {
                if !days.isEmpty {
                    dayPicker(days: days)
                    let day = days[safeIndex]
                    let metrics = DayMetrics(day: day)

                    gassiScoreBadge(metrics: metrics)
                    summaryCard(day: day, metrics: metrics)
                    statsGrid(metrics: metrics)
                    rainTimeline(weather: weather, day: day, isToday: safeIndex == 0)
                    hundeHinweise(day: day, metrics: metrics)
                    schnueffelCard(metrics: metrics)
                }

                Text("Wetterdaten von Apple WeatherKit. Gassi-Score, Asphalt-Temperatur und Hunde-Hinweise werden lokal berechnet — identische Formeln wie banyaro.app.")
                    .font(.caption2)
                    .foregroundStyle(.tertiary)
                    .padding(.top, 8)
            }
            .padding()
        }
    }

    // MARK: - Day picker

    private func dayPicker(days: [DayWeather]) -> some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack(spacing: 8) {
                ForEach(Array(days.enumerated()), id: \.offset) { i, day in
                    Button {
                        selectedDayIndex = i
                    } label: {
                        VStack(spacing: 4) {
                            Text(dayLabel(day.date, index: i))
                                .font(.caption.bold())
                            Image(systemName: day.symbolName)
                                .symbolRenderingMode(.multicolor)
                                .font(.title3)
                            Text("\(Int(day.highTemperature.converted(to: .celsius).value.rounded()))°")
                                .font(.subheadline.bold().monospacedDigit())
                        }
                        .frame(width: 56)
                        .padding(.vertical, 10)
                        .background(
                            i == selectedDayIndex ? Color.accentColor : Color.secondary.opacity(0.12),
                            in: RoundedRectangle(cornerRadius: 12)
                        )
                        .foregroundStyle(i == selectedDayIndex ? .white : .primary)
                    }
                    .buttonStyle(.plain)
                }
            }
        }
    }

    private func dayLabel(_ date: Date, index: Int) -> String {
        if index == 0 { return "Heute" }
        if index == 1 { return "Morgen" }
        let f = DateFormatter()
        f.locale = Locale(identifier: "de_DE")
        f.dateFormat = "EEE"
        return f.string(from: date)
    }

    // MARK: - Gassi-Score Badge

    private func gassiScoreBadge(metrics: DayMetrics) -> some View {
        let badge = GassiWetter.GassiScoreBadge(score: metrics.gassiScore)
        let color = Color(hex: badge.colorHex)
        return HStack(spacing: 14) {
            Text("🐾").font(.system(size: 32))
            VStack(alignment: .leading, spacing: 2) {
                Text("Gassi-Score").font(.caption.bold()).foregroundStyle(.secondary)
                HStack(alignment: .firstTextBaseline, spacing: 4) {
                    Text("\(badge.score)").font(.system(size: 40, weight: .heavy, design: .rounded))
                    Text("/ 10").font(.title3.bold()).foregroundStyle(.secondary)
                }
                Text(badge.label).font(.subheadline.bold()).foregroundStyle(color)
            }
            Spacer()
        }
        .padding(16)
        .background(color.opacity(0.15), in: RoundedRectangle(cornerRadius: 16))
        .overlay(
            RoundedRectangle(cornerRadius: 16)
                .stroke(color.opacity(0.5), lineWidth: 1.5)
        )
    }

    // MARK: - Summary card

    private func summaryCard(day: DayWeather, metrics: DayMetrics) -> some View {
        HStack(spacing: 14) {
            Image(systemName: day.symbolName)
                .symbolRenderingMode(.multicolor)
                .font(.system(size: 56))
            VStack(alignment: .leading, spacing: 2) {
                Text(germanCondition(day.condition))
                    .font(.headline)
                HStack(spacing: 6) {
                    Text("\(Int(metrics.tempMax.rounded()))°").font(.title3.bold().monospacedDigit())
                    Text("/ \(Int(metrics.tempMin.rounded()))°")
                        .font(.subheadline.monospacedDigit())
                        .foregroundStyle(.secondary)
                }
            }
            Spacer()
        }
        .padding(16)
        .background(.background.secondary, in: RoundedRectangle(cornerRadius: 16))
    }

    // MARK: - Stats grid

    private func statsGrid(metrics: DayMetrics) -> some View {
        let cols = [GridItem(.flexible()), GridItem(.flexible())]
        return LazyVGrid(columns: cols, spacing: 10) {
            statCell(icon: "umbrella.fill", color: .blue,
                     value: "\(metrics.precipPct) %", label: "Niederschlag")
            statCell(icon: "wind", color: .gray,
                     value: "\(Int(metrics.windKmh.rounded())) km/h", label: "Wind")
            statCell(icon: "sun.max.fill", color: .orange,
                     value: "\(metrics.uvIndex)", label: "UV-Index")
            statCell(icon: "thermometer.sun.fill", color: .red,
                     value: "\(Int(metrics.asphalt.rounded()))°", label: "Asphalt")
        }
    }

    private func statCell(icon: String, color: Color, value: String, label: String) -> some View {
        HStack(spacing: 10) {
            Image(systemName: icon)
                .foregroundStyle(color)
                .frame(width: 28)
            VStack(alignment: .leading, spacing: 2) {
                Text(value).font(.subheadline.bold().monospacedDigit())
                Text(label).font(.caption).foregroundStyle(.secondary)
            }
            Spacer()
        }
        .padding(12)
        .background(.background.secondary, in: RoundedRectangle(cornerRadius: 12))
    }

    // MARK: - Niederschlags-Timeline

    private func rainTimeline(weather: Weather, day: DayWeather, isToday: Bool) -> some View {
        let hours = relevantHours(weather: weather, day: day, isToday: isToday)
        let maxMm = max(hours.map { $0.precipitationAmount.converted(to: .millimeters).value }.max() ?? 0, 0.5)
        let totalChance = hours.reduce(0.0) { $0 + $1.precipitationChance } / Double(max(1, hours.count))

        return VStack(alignment: .leading, spacing: 10) {
            HStack {
                Label("Niederschlag", systemImage: "umbrella.fill")
                    .font(.headline)
                    .foregroundStyle(.blue)
                Spacer()
                Text(headerLabel(isToday: isToday, totalChance: totalChance))
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }

            if hours.isEmpty {
                Text("Keine stündlichen Daten verfügbar.")
                    .font(.caption)
                    .foregroundStyle(.secondary)
            } else {
                ScrollView(.horizontal, showsIndicators: false) {
                    HStack(alignment: .bottom, spacing: 6) {
                        ForEach(Array(hours.enumerated()), id: \.offset) { _, hour in
                            rainBar(for: hour, scaleMm: maxMm)
                        }
                    }
                    .frame(height: 110)
                }
            }
        }
        .padding(14)
        .background(.background.secondary, in: RoundedRectangle(cornerRadius: 12))
    }

    private func relevantHours(weather: Weather, day: DayWeather, isToday: Bool) -> [HourWeather] {
        let all = weather.hourlyForecast
        if isToday {
            // Ab jetzt die nächsten 12 Stunden
            return Array(all.filter { $0.date >= .now }.prefix(12))
        }
        // Der ausgewählte Tag, 06:00 bis 22:00
        let cal = Calendar.current
        return all
            .filter { cal.isDate($0.date, inSameDayAs: day.date) }
            .filter {
                let h = cal.component(.hour, from: $0.date)
                return h >= 6 && h <= 22
            }
    }

    private func rainBar(for hour: HourWeather, scaleMm: Double) -> some View {
        let chance = hour.precipitationChance
        let mm = hour.precipitationAmount.converted(to: .millimeters).value
        // Höhe primär aus mm, mindestens 6 (auch bei 0 sichtbarer Bar-Sockel)
        let height: CGFloat = max(6, CGFloat(mm / scaleMm) * 50)
        let intensity: Double = min(1.0, chance + mm / 5)
        let baseColor = Color.blue
        return VStack(spacing: 3) {
            Text("\(Int((chance * 100).rounded()))%")
                .font(.caption2.monospacedDigit())
                .foregroundStyle(chance >= 0.3 ? .primary : .secondary)
            Rectangle()
                .fill(LinearGradient(
                    colors: [baseColor.opacity(0.4 + 0.6 * intensity), baseColor.opacity(0.2 + 0.2 * intensity)],
                    startPoint: .top,
                    endPoint: .bottom
                ))
                .frame(width: 22, height: height)
                .clipShape(RoundedRectangle(cornerRadius: 4))
            Text(hourLabel(hour.date))
                .font(.caption2.monospacedDigit())
                .foregroundStyle(.secondary)
        }
        .frame(height: 100, alignment: .bottom)
    }

    private func hourLabel(_ date: Date) -> String {
        let f = DateFormatter()
        f.locale = Locale(identifier: "de_DE")
        f.dateFormat = "HH"
        return "\(f.string(from: date)):00"
    }

    private func headerLabel(isToday: Bool, totalChance: Double) -> String {
        let pct = Int((totalChance * 100).rounded())
        let prefix = isToday ? "nächste 12 h" : "06–22 h"
        if totalChance < 0.05 { return "\(prefix) · trocken" }
        return "\(prefix) · ⌀ \(pct) % Regen"
    }

    // MARK: - Hunde-Hinweise

    private func hundeHinweise(day: DayWeather, metrics: DayMetrics) -> some View {
        VStack(alignment: .leading, spacing: 8) {
            Label("Hunde-Hinweise", systemImage: "pawprint.fill")
                .font(.headline)
                .foregroundStyle(Color.accentColor)

            // Asphalt
            let level = GassiWetter.asphaltLevel(for: metrics.asphalt)
            hintBox(
                icon: "thermometer.sun.fill",
                color: asphaltColor(for: level),
                title: "Asphalt ~\(Int(metrics.asphalt.rounded()))°C — \(level.label)",
                detail: level.advice
            )

            // Pfoten-Kälteschutz
            if GassiWetter.pawColdProtection(tempMin: metrics.tempMin) {
                hintBox(
                    icon: "snowflake",
                    color: .blue,
                    title: "Pfoten-Kälteschutz",
                    detail: "Eis und Streusalz reizen die Pfoten. Pfotenpflege empfohlen, ggf. Schuhe."
                )
            }

            // Gewitter
            if metrics.thunderstorm {
                hintBox(
                    icon: "cloud.bolt.fill",
                    color: .purple,
                    title: "Gewitter erwartet",
                    detail: "Hunde reagieren oft sensibel. Sichere, ruhige Umgebung schaffen."
                )
            }

            // Zecken
            let month = Calendar.current.component(.month, from: day.date)
            let tick = GassiWetter.tickRisk(tempMax: metrics.tempMax, month: month)
            if tick != .none {
                hintBox(
                    icon: "ant.fill",
                    color: Color(hex: tick.colorHex),
                    title: "Zecken-Risiko: \(tick.label)",
                    detail: tick == .high ? "Nach jedem Spaziergang absuchen, Schutzmittel verwenden." : nil
                )
            }
        }
    }

    private func hintBox(icon: String, color: Color, title: String, detail: String?) -> some View {
        HStack(alignment: .top, spacing: 10) {
            Image(systemName: icon)
                .foregroundStyle(color)
                .frame(width: 24)
            VStack(alignment: .leading, spacing: 2) {
                Text(title).font(.subheadline.bold()).foregroundStyle(color)
                if let detail {
                    Text(detail).font(.caption).foregroundStyle(.secondary)
                }
            }
            Spacer()
        }
        .padding(12)
        .background(color.opacity(0.12), in: RoundedRectangle(cornerRadius: 12))
        .overlay(
            RoundedRectangle(cornerRadius: 12)
                .stroke(color.opacity(0.35), lineWidth: 1)
        )
    }

    private func asphaltColor(for level: GassiWetter.AsphaltLevel) -> Color {
        switch level {
        case .safe:   return .green
        case .warm:   return .yellow
        case .hot:    return .orange
        case .danger: return .red
        }
    }

    // MARK: - Schnüffel-Index

    private func schnueffelCard(metrics: DayMetrics) -> some View {
        let idx = GassiWetter.schnueffelIndex(tempMax: metrics.tempMax, precipProb: metrics.precipPct)
        let color = Color(hex: idx.colorHex)
        return HStack(spacing: 12) {
            Text(idx.emoji).font(.title)
            VStack(alignment: .leading, spacing: 2) {
                Text("Schnüffel-Index").font(.caption.bold()).foregroundStyle(.secondary)
                Text(idx.label).font(.subheadline.bold()).foregroundStyle(color)
            }
            Spacer()
        }
        .padding(14)
        .background(color.opacity(0.12), in: RoundedRectangle(cornerRadius: 12))
    }

    // MARK: - Loading

    private func germanCondition(_ condition: WeatherCondition) -> String {
        switch condition {
        case .clear:                    return "Klar"
        case .mostlyClear:              return "Überwiegend klar"
        case .partlyCloudy:             return "Teilweise bewölkt"
        case .mostlyCloudy:             return "Überwiegend bewölkt"
        case .cloudy:                   return "Bedeckt"
        case .foggy:                    return "Nebel"
        case .haze:                     return "Dunst"
        case .smoky:                    return "Rauch in der Luft"
        case .drizzle:                  return "Nieselregen"
        case .freezingDrizzle:          return "Gefrierender Nieselregen"
        case .rain:                     return "Regen"
        case .heavyRain:                return "Starker Regen"
        case .freezingRain:             return "Gefrierender Regen"
        case .sunShowers:               return "Sonnige Schauer"
        case .snow:                     return "Schnee"
        case .heavySnow:                return "Starker Schnee"
        case .flurries:                 return "Schneetreiben"
        case .blowingSnow:              return "Schneeverwehung"
        case .blizzard:                 return "Schneesturm"
        case .sleet:                    return "Schneeregen"
        case .hail:                     return "Hagel"
        case .wintryMix:                return "Schneeregen-Mix"
        case .thunderstorms:            return "Gewitter"
        case .strongStorms:             return "Starkes Gewitter"
        case .scatteredThunderstorms:   return "Vereinzelte Gewitter"
        case .isolatedThunderstorms:    return "Einzelne Gewitter"
        case .tropicalStorm:            return "Tropensturm"
        case .hurricane:                return "Hurrikan"
        case .hot:                      return "Hitze"
        case .frigid:                   return "Eisige Kälte"
        case .windy:                    return "Windig"
        case .breezy:                   return "Leichte Brise"
        case .blowingDust:              return "Staubsturm"
        case .sunFlurries:              return "Schneetreiben"
        default:                        return condition.description
        }
    }

    private func loadWeather() async {
        guard let coord = location.coordinate else { return }
        isLoading = true
        errorMessage = nil
        defer { isLoading = false }
        let loc = CLLocation(latitude: coord.latitude, longitude: coord.longitude)
        do {
            weather = try await WeatherService.shared.weather(for: loc)
        } catch {
            errorMessage = error.localizedDescription
        }
    }
}

// MARK: - Day metrics derived from DayWeather

private struct DayMetrics {
    let tempMax: Double
    let tempMin: Double
    let precipPct: Int
    let windKmh: Double
    let uvIndex: Int
    let thunderstorm: Bool
    let asphalt: Double
    let gassiScore: Int

    init(day: DayWeather) {
        let tMax = day.highTemperature.converted(to: .celsius).value
        let tMin = day.lowTemperature.converted(to: .celsius).value
        let pct = Int((day.precipitationChance * 100).rounded())
        let wind = day.wind.speed.converted(to: .kilometersPerHour).value
        let uv = day.uvIndex.value
        let thunder = [
            WeatherCondition.thunderstorms,
            .strongStorms,
            .scatteredThunderstorms,
            .isolatedThunderstorms
        ].contains(day.condition)
        let asphaltT = GassiWetter.asphaltTemp(airMax: tMax, uvMax: Double(uv))

        self.tempMax = tMax
        self.tempMin = tMin
        self.precipPct = pct
        self.windKmh = wind
        self.uvIndex = uv
        self.thunderstorm = thunder
        self.asphalt = asphaltT
        self.gassiScore = GassiWetter.gassiScore(
            tempMax: tMax,
            precipProb: pct,
            windKmh: wind,
            asphalt: asphaltT,
            thunderstorm: thunder
        )
    }
}
